diff --git a/include/serialport.h b/include/serialport.h index ca0d72b3..5879a444 100644 --- a/include/serialport.h +++ b/include/serialport.h @@ -16,16 +16,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: serialport.h,v 1.17 2009-05-27 09:15:41 qbix79 Exp $ */ +/* $Id: serialport.h,v 1.18 2009-09-25 23:40:48 h-a-l-9000 Exp $ */ #ifndef DOSBOX_SERIALPORT_H #define DOSBOX_SERIALPORT_H -#define SERIAL_DEBUG 0 - -// Uncomment this for a lot of debug messages: -//#define LOG_UART - #ifndef DOSBOX_DOSBOX_H #include "dosbox.h" #endif @@ -42,12 +37,91 @@ #include "programs.h" #endif +// set this to 1 for serial debugging in release mode +#define SERIAL_DBG_FORCED 0 + +#if (C_DEBUG || SERIAL_DBG_FORCED) +#define SERIAL_DEBUG 1 +#endif + #if SERIAL_DEBUG #include "hardware.h" #endif // Serial port interface +class MyFifo { +public: + MyFifo(Bitu maxsize_) { + maxsize=size=maxsize_; + pos=used=0; + data=new Bit8u[size]; + } + ~MyFifo() { + delete[] data; + } + INLINE Bitu getFree(void) { + return size-used; + } + bool isEmpty() { + return used==0; + } + bool isFull() { + return (size-used)==0; + } + + INLINE Bitu getUsage(void) { + return used; + } + void setSize(Bitu newsize) + { + size=newsize; + pos=used=0; + } + void clear(void) { + pos=used=0; + data[0]=0; + } + + bool addb(Bit8u _val) { + Bitu where=pos+used; + if (where>=size) where-=size; + if(used>=size) { + // overwrite last byte + if(where==0) where=size-1; + else where--; + data[where]=_val; + return false; + } + data[where]=_val; + used++; + return true; + } + Bit8u getb() { + if (!used) return data[pos]; + Bitu where=pos; + if (++pos>=size) pos-=size; + used--; + return data[where]; + } + Bit8u getTop() { + Bitu where=pos+used; + if (where>=size) where-=size; + if(used>=size) { + if(where==0) where=size-1; + else where--; + } + return data[where]; + } + + Bit8u probeByte() { + return data[pos]; + } +private: + Bit8u * data; + Bitu maxsize,size,pos,used; +}; + class CSerial { public: @@ -58,7 +132,7 @@ public: bool dbg_register; bool dbg_interrupt; bool dbg_aux; - + void log_ser(bool active, char const* format,...); #endif static bool getBituSubstring(const char* name,Bitu* data, CommandLine* cmd); @@ -92,8 +166,9 @@ public: #define SERIAL_RX_EVENT 4 #define SERIAL_POLLING_EVENT 5 #define SERIAL_THR_EVENT 6 +#define SERIAL_RX_TIMEOUT_EVENT 7 -#define SERIAL_BASE_EVENT_COUNT 6 +#define SERIAL_BASE_EVENT_COUNT 7 #define COMNUMBER idnumber+1 @@ -144,6 +219,7 @@ public: // If a byte comes from loopback or prepherial, put it in here. void receiveByte(Bit8u data); + void receiveByteEx(Bit8u data, Bit8u error); // If an error was received, put it here (in LSR register format) void receiveError(Bit8u errorword); @@ -177,7 +253,7 @@ private: DOS_Device* mydosdevice; - // I used this spec: http://www.exar.com/products/st16c450v420.pdf + // I used this spec: st16c450v420.pdf void ComputeInterrupts(); @@ -191,23 +267,20 @@ private: #define RX_PRIORITY 1 // a byte has been received #define TX_PRIORITY 2 // tx buffer has become empty #define MSR_PRIORITY 8 // CRS, DSR, RI, DCD change + #define TIMEOUT_PRIORITY 0x10 #define NONE_PRIORITY 0 Bit8u waiting_interrupts; // these are on, but maybe not enabled - // 16C450 (no FIFO) + // 16C550 // read/write name Bit16u baud_divider; - Bit8u RHR; // r Receive Holding Register, also LSB of Divisor Latch (r/w) - #define RHR_OFFSET 0 - // Data: whole byte - - Bit8u THR; // w Transmit Holding Register - #define THR_OFFSET 0 - // Data: whole byte - - Bit8u IER; // r/w Interrupt Enable Register, also MSB of Divisor Latch + #define RHR_OFFSET 0 // r Receive Holding Register, also LSB of Divisor Latch (r/w) + // Data: whole byte + #define THR_OFFSET 0 // w Transmit Holding Register + // Data: whole byte + Bit8u IER; // r/w Interrupt Enable Register, also MSB of Divisor Latch #define IER_OFFSET 1 bool irq_active; @@ -221,6 +294,7 @@ private: #define ISR_OFFSET 2 #define ISR_CLEAR_VAL 0x1 + #define ISR_FIFOTIMEOUT_VAL 0xc #define ISR_ERROR_VAL 0x6 #define ISR_RX_VAL 0x4 #define ISR_TX_VAL 0x2 @@ -292,6 +366,7 @@ private: Bitu framingErrors; Bitu parityErrors; Bitu overrunErrors; + Bitu txOverrunErrors; Bitu overrunIF0; Bitu breakErrors; @@ -329,16 +404,28 @@ private: void transmitLoopbackByte(Bit8u val, bool value); // 16C550 (FIFO) - // TODO + public: // todo remove + MyFifo* rxfifo; + private: + MyFifo* txfifo; + MyFifo* errorfifo; + Bitu errors_in_fifo; + Bitu rx_interrupt_threshold; + Bitu fifosize; + Bit8u FCR; + bool sync_guardtime; + #define FIFO_STATUS_ACTIVE 0xc0 // FIFO is active AND works ;) + #define FIFO_ERROR 0x80 + #define FCR_ACTIVATE 0x01 + #define FCR_CLEAR_RX 0x02 + #define FCR_CLEAR_TX 0x04 #define FCR_OFFSET 2 - bool fifo_warn; - //Bit8u FCR; // FIFO Control Register - + #define FIFO_FLOWCONTROL 0x20 }; extern CSerial* serialports[]; -const Bit8u serial_defaultirq[4] = { 4, 3, 4, 3 }; -const Bit16u serial_baseaddr[4] = {0x3f8,0x2f8,0x3e8,0x2e8}; +const Bit8u serial_defaultirq[] = { 4, 3, 4, 3 }; +const Bit16u serial_baseaddr[] = {0x3f8,0x2f8,0x3e8,0x2e8}; const char* const serial_comname[]={"COM1","COM2","COM3","COM4"}; // the COM devices @@ -358,4 +445,3 @@ private: }; #endif - diff --git a/src/hardware/serialport/Makefile.am b/src/hardware/serialport/Makefile.am index af7b803c..d2e72005 100644 --- a/src/hardware/serialport/Makefile.am +++ b/src/hardware/serialport/Makefile.am @@ -2,9 +2,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/include noinst_LIBRARIES = libserial.a -libserial_a_SOURCES = directserial_win32.cpp directserial_win32.h \ - serialdummy.cpp serialdummy.h serialport.cpp \ - softmodem.cpp softmodem.h misc_util.cpp misc_util.h \ - directserial_os2.h directserial_os2.cpp \ - directserial_posix.h directserial_posix.cpp \ - nullmodem.cpp nullmodem.h +libserial_a_SOURCES = directserial.cpp directserial.h \ + libserial.cpp libserial.h \ + serialdummy.cpp serialdummy.h serialport.cpp \ + softmodem.cpp softmodem.h misc_util.cpp misc_util.h \ + nullmodem.cpp nullmodem.h diff --git a/src/hardware/serialport/directserial.cpp b/src/hardware/serialport/directserial.cpp new file mode 100644 index 00000000..1e591264 --- /dev/null +++ b/src/hardware/serialport/directserial.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2002-2007 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: directserial.cpp,v 1.1 2009-09-25 23:40:47 h-a-l-9000 Exp $ */ + +#include "dosbox.h" + +#if C_DIRECTSERIAL + +#include "serialport.h" +#include "directserial.h" +#include "misc_util.h" +#include "pic.h" + +#include "libserial.h" + +/* This is a serial passthrough class. Its amazingly simple to */ +/* write now that the serial ports themselves were abstracted out */ + +CDirectSerial::CDirectSerial (Bitu id, CommandLine* cmd) + :CSerial (id, cmd) { + InstallationSuccessful = false; + comport = 0; + + rx_retry = 0; + rx_retry_max = 0; + + std::string tmpstring; + if(!cmd->FindStringBegin("realport:",tmpstring,false)) return; + + LOG_MSG ("Serial%d: Opening %s", COMNUMBER, tmpstring.c_str()); + if(!SERIAL_open(tmpstring.c_str(), &comport)) { + char errorbuffer[256]; + SERIAL_getErrorString(errorbuffer, sizeof(errorbuffer)); + LOG_MSG("Serial%d: Serial Port \"%s\" could not be opened.", + COMNUMBER, tmpstring.c_str()); + LOG_MSG("%s",errorbuffer); + return; + } + +#if SERIAL_DEBUG + dbgmsg_poll_block=false; + dbgmsg_rx_block=false; +#endif + + // rxdelay: How many milliseconds to wait before causing an + // overflow when the application is unresponsive. + if(getBituSubstring("rxdelay:", &rx_retry_max, cmd)) { + if(!(rx_retry_max<=10000)) { + rx_retry_max=0; + } + } + + CSerial::Init_Registers(); + InstallationSuccessful = true; + rx_state = D_RX_IDLE; + setEvent(SERIAL_POLLING_EVENT, 1); // millisecond receive tick +} + +CDirectSerial::~CDirectSerial () { + if(comport) SERIAL_close(comport); + // We do not use own events so we don't have to clear them. +} + +// CanReceive: true:UART part has room left +// doReceive: true:there was really a byte to receive +// rx_retry is incremented in polling events + +// in POLLING_EVENT: always add new polling event +// D_RX_IDLE + CanReceive + doReceive -> D_RX_WAIT , add RX_EVENT +// D_RX_IDLE + CanReceive + not doReceive -> D_RX_IDLE +// D_RX_IDLE + not CanReceive -> D_RX_BLOCKED, add RX_EVENT + +// D_RX_BLOCKED + CanReceive + doReceive -> D_RX_FASTWAIT, rem RX_EVENT +// rx_retry=0 , add RX_EVENT +// D_RX_BLOCKED + CanReceive + !doReceive -> D_RX_IDLE, rem RX_EVENT +// rx_retry=0 +// D_RX_BLOCKED + !CanReceive + doReceive + retry < max -> D_RX_BLOCKED, rx_retry++ +// D_RX_BLOCKED + !CanReceive + doReceive + retry >=max -> rx_retry=0 + +// to be continued... + +void CDirectSerial::handleUpperEvent(Bit16u type) { + switch(type) { + case SERIAL_POLLING_EVENT: { + setEvent(SERIAL_POLLING_EVENT, 1.0f); + // update Modem input line states + switch(rx_state) { + case D_RX_IDLE: + if(CanReceiveByte()) { + if(doReceive()) { + // a byte was received + rx_state=D_RX_WAIT; + setEvent(SERIAL_RX_EVENT, bytetime*0.9f); + } // else still idle + } else { +#if SERIAL_DEBUG + if(!dbgmsg_poll_block) { + log_ser(dbg_aux,"Directserial: block on polling."); + dbgmsg_poll_block=true; + } +#endif + rx_state=D_RX_BLOCKED; + // have both delays (1ms + bytetime) + setEvent(SERIAL_RX_EVENT, bytetime*0.9f); + } + break; + case D_RX_BLOCKED: + // one timeout tick + if(!CanReceiveByte()) { + rx_retry++; + if(rx_retry>=rx_retry_max) { + // it has timed out: + rx_retry=0; + removeEvent(SERIAL_RX_EVENT); + if(doReceive()) { + // read away everything + // this will set overrun errors + while(doReceive()); + rx_state=D_RX_WAIT; + setEvent(SERIAL_RX_EVENT, bytetime*0.9f); + } else { + // much trouble about nothing + rx_state=D_RX_IDLE; + } + } // else wait further + } else { + // good: we can receive again +#if SERIAL_DEBUG + dbgmsg_poll_block=false; + dbgmsg_rx_block=false; +#endif + removeEvent(SERIAL_RX_EVENT); + rx_retry=0; + if(doReceive()) { + rx_state=D_RX_FASTWAIT; + setEvent(SERIAL_RX_EVENT, bytetime*0.65f); + } else { + // much trouble about nothing + rx_state=D_RX_IDLE; + } + } + break; + + case D_RX_WAIT: + case D_RX_FASTWAIT: + break; + } + updateMSR(); + break; + } + case SERIAL_RX_EVENT: { + switch(rx_state) { + case D_RX_IDLE: + LOG_MSG("internal error in directserial"); + break; + + case D_RX_BLOCKED: // try to receive + case D_RX_WAIT: + case D_RX_FASTWAIT: + if(CanReceiveByte()) { + // just works or unblocked + rx_retry=0; // not waiting anymore + if(doReceive()) { + if(rx_state==D_RX_WAIT) setEvent(SERIAL_RX_EVENT, bytetime*0.9f); + else { + // maybe unblocked + rx_state=D_RX_FASTWAIT; + setEvent(SERIAL_RX_EVENT, bytetime*0.65f); + } + } else { + // didn't receive anything + rx_state=D_RX_IDLE; + } + } else { + // blocking now or still blocked +#if SERIAL_DEBUG + if(rx_state==D_RX_BLOCKED) { + if(!dbgmsg_rx_block) { + log_ser(dbg_aux,"Directserial: rx still blocked (retry=%d)",rx_retry); + dbgmsg_rx_block=true; + } + } + + + + + + + else log_ser(dbg_aux,"Directserial: block on continued rx (retry=%d).",rx_retry); +#endif + setEvent(SERIAL_RX_EVENT, bytetime*0.65f); + rx_state=D_RX_BLOCKED; + } + + break; + } + updateMSR(); + break; + } + case SERIAL_TX_EVENT: { + // Maybe echo cirquit works a bit better this way + if(rx_state==D_RX_IDLE && CanReceiveByte()) { + if(doReceive()) { + // a byte was received + rx_state=D_RX_WAIT; + setEvent(SERIAL_RX_EVENT, bytetime*0.9f); + } + } + ByteTransmitted(); + updateMSR(); + break; + } + case SERIAL_THR_EVENT: { + ByteTransmitting(); + setEvent(SERIAL_TX_EVENT,bytetime*1.1f); + break; + } + } +} + +bool CDirectSerial::doReceive() { + int value = SERIAL_getextchar(comport); + if(value) { + receiveByteEx((Bit8u)(value&0xff),(Bit8u)((value&0xff00)>>8)); + return true; + } + return false; +} + +// updatePortConfig is called when emulated app changes the serial port +// parameters baudrate, stopbits, number of databits, parity. +void CDirectSerial::updatePortConfig (Bit16u divider, Bit8u lcr) { + Bit8u parity = 0; + + switch ((lcr & 0x38)>>3) { + case 0x1: parity='o'; break; + case 0x3: parity='e'; break; + case 0x5: parity='m'; break; + case 0x7: parity='s'; break; + default: parity='n'; break; + } + + Bit8u bytelength = (lcr & 0x3)+5; + + // baudrate + Bitu baudrate; + if(divider==0) baudrate=115200; + else baudrate = 115200 / divider; + + // stopbits + Bit8u stopbits; + if (lcr & 0x4) { + if (bytelength == 5) stopbits = SERIAL_15STOP; + else stopbits = SERIAL_2STOP; + } else stopbits = SERIAL_1STOP; + + if(!SERIAL_setCommParameters(comport, baudrate, parity, stopbits, bytelength)) { +#if SERIAL_DEBUG + log_ser(dbg_aux,"Serial port settings not supported by host." ); +#endif + LOG_MSG ("Serial%d: Desired serial mode not supported (%d,%d,%c,%d)", + COMNUMBER, baudrate,bytelength,parity,stopbits); + } + CDirectSerial::setRTSDTR(getRTS(), getDTR()); +} + +void CDirectSerial::updateMSR () { + int new_status = SERIAL_getmodemstatus(comport); + + setCTS(new_status&SERIAL_CTS? true:false); + setDSR(new_status&SERIAL_DSR? true:false); + setRI(new_status&SERIAL_RI? true:false); + setCD(new_status&SERIAL_CD? true:false); +} + +void CDirectSerial::transmitByte (Bit8u val, bool first) { + if(!SERIAL_sendchar(comport, val)) + LOG_MSG("Serial%d: COM port error: write failed!", COMNUMBER); + if(first) setEvent(SERIAL_THR_EVENT, bytetime/8); + else setEvent(SERIAL_TX_EVENT, bytetime); +} + + +// setBreak(val) switches break on or off +void CDirectSerial::setBreak (bool value) { + SERIAL_setBREAK(comport,value); +} + +// updateModemControlLines(mcr) sets DTR and RTS. +void CDirectSerial::setRTSDTR(bool rts, bool dtr) { + SERIAL_setRTS(comport,rts); + SERIAL_setDTR(comport,dtr); +} + +void CDirectSerial::setRTS(bool val) { + SERIAL_setRTS(comport,val); +} + +void CDirectSerial::setDTR(bool val) { + SERIAL_setDTR(comport,val); +} + +#endif diff --git a/src/hardware/serialport/directserial_win32.h b/src/hardware/serialport/directserial.h similarity index 72% rename from src/hardware/serialport/directserial_win32.h rename to src/hardware/serialport/directserial.h index a2757f1a..e5efe880 100644 --- a/src/hardware/serialport/directserial_win32.h +++ b/src/hardware/serialport/directserial.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2007 The DOSBox Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: directserial_win32.h,v 1.6 2009-05-27 09:15:41 qbix79 Exp $ */ +/* $Id: directserial.h,v 1.1 2009-09-25 23:40:47 h-a-l-9000 Exp $ */ // include guard #ifndef DOSBOX_DIRECTSERIAL_WIN32_H @@ -25,33 +25,17 @@ #include "dosbox.h" #if C_DIRECTSERIAL -#ifdef WIN32 - - #define DIRECTSERIAL_AVAILIBLE #include "serialport.h" -#include //To prevent compilation problems with windows.h including winsock.h -#include + +#include "libserial.h" class CDirectSerial : public CSerial { public: - HANDLE hCom; - DCB dcb; - BOOL fSuccess; - - CDirectSerial(Bitu id, CommandLine* cmd/*const char* configstring*/); + CDirectSerial(Bitu id, CommandLine* cmd); ~CDirectSerial(); - bool receiveblock; // It's not a block of data it rather blocks - Bitu rx_retry; // counter of retries - - Bitu rx_retry_max; // how many POLL_EVENTS to wait before causing - // a overrun error. - - - void CheckErrors(); - void updatePortConfig(Bit16u divider, Bit8u lcr); void updateMSR(); void transmitByte(Bit8u val, bool first); @@ -61,9 +45,27 @@ public: void setRTS(bool val); void setDTR(bool val); void handleUpperEvent(Bit16u type); - + +private: + COMPORT comport; + + Bitu rx_state; +#define D_RX_IDLE 0 +#define D_RX_WAIT 1 +#define D_RX_BLOCKED 2 +#define D_RX_FASTWAIT 3 + + Bitu rx_retry; // counter of retries (every millisecond) + Bitu rx_retry_max; // how many POLL_EVENTS to wait before causing + // an overrun error. + bool doReceive(); + +#if SERIAL_DEBUG + bool dbgmsg_poll_block; + bool dbgmsg_rx_block; +#endif + }; -#endif // WIN32 #endif // C_DIRECTSERIAL #endif // include guard diff --git a/src/hardware/serialport/directserial_os2.cpp b/src/hardware/serialport/directserial_os2.cpp deleted file mode 100644 index e1626641..00000000 --- a/src/hardware/serialport/directserial_os2.cpp +++ /dev/null @@ -1,515 +0,0 @@ -/* - * Copyright (C) 2002-2009 The DOSBox Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* $Id: directserial_os2.cpp,v 1.5 2009-05-27 09:15:41 qbix79 Exp $ */ - -#include "dosbox.h" - -#if C_DIRECTSERIAL - - -#if defined(OS2) -#include "serialport.h" -#include "directserial_os2.h" -#include "misc_util.h" -#include "pic.h" - -// OS/2 related headers -#define INCL_DOSFILEMGR -#define INCL_DOSERRORS -#define INCL_DOSDEVICES -#define INCL_DOSDEVIOCTL -#define INCL_DOSPROCESS -#include - -/* This is a serial passthrough class. Its amazingly simple to */ -/* write now that the serial ports themselves were abstracted out */ - -CDirectSerial::CDirectSerial (Bitu id, CommandLine *cmd) - : CSerial(id, cmd) { - InstallationSuccessful = false; - - - rx_retry = 0; - rx_retry_max = 0; - - std::string tmpstring; - - if (!cmd->FindStringBegin("realport:", tmpstring, false)) - { - return; - } -#if SERIAL_DEBUG - if (dbg_modemcontrol) - { - fprintf(debugfp, "%12.3f Port type directserial realport %s\r\n", PIC_FullIndex(), tmpstring.c_str()); - } -#endif - - - // rxdelay: How many milliseconds to wait before causing an - // overflow when the application is unresponsive. - if(getBituSubstring("rxdelay:", &rx_retry_max, cmd)) { - if(!(rx_retry_max<=10000)) { - rx_retry_max=0; - } - } - - const char* tmpchar=tmpstring.c_str(); - - LOG_MSG ("Serial%d: Opening %s", COMNUMBER, tmpstring.c_str()); - - ULONG ulAction = 0; - APIRET rc = DosOpen((unsigned char*)tmpstring.c_str(), &hCom, &ulAction, 0L, FILE_NORMAL, FILE_OPEN, - OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE | OPEN_FLAGS_SEQUENTIAL, 0L); - if (rc != NO_ERROR) - { - LOG_MSG ("Serial%d: Serial port \"%s\" could not be opened.", COMNUMBER, tmpstring.c_str()); - if (rc == 2) { - LOG_MSG ("The specified port does not exist."); - } else if (rc == 99) { - LOG_MSG ("The specified port is already in use."); - } else { - LOG_MSG ("OS/2 error %d occurred.", rc); - } - - hCom = 0; - return; - } - - DCBINFO dcb; - ULONG ulParmLen = sizeof(DCBINFO); - rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETDCBINFO, 0, 0, 0, &dcb, ulParmLen, &ulParmLen); - if ( rc != NO_ERROR) - { - LOG_MSG("GetCommState failed with error %d.\n", rc); - DosClose(hCom); - hCom = 0; - return; - } - - dcb.usWriteTimeout = 0; - dcb.usReadTimeout = 0; //65535; - dcb.fbCtlHndShake = dcb.fbFlowReplace = 0; - dcb.fbTimeout = 6; - rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcb, ulParmLen, &ulParmLen, 0, 0, 0); - if ( rc != NO_ERROR) - { - LOG_MSG("SetDCBInfo failed with error %d.\n", rc); - DosClose(hCom); - hCom = 0; - return; - } - - - struct { - ULONG baud; - BYTE fraction; - } setbaud; - setbaud.baud = 9600; - setbaud.fraction = 0; - ulParmLen = sizeof(setbaud); - rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_EXTSETBAUDRATE, &setbaud, ulParmLen, &ulParmLen, 0, 0, 0); - if (rc != NO_ERROR) - { - LOG_MSG("ExtSetBaudrate failed with error %d.\n", rc); - DosClose (hCom); - hCom = 0; - return; -} - - struct { - UCHAR data; - UCHAR parity; - UCHAR stop; - } paramline; - - // byte length - paramline.data = 8; - paramline.parity = 0; - paramline.stop = 0; - ulParmLen = sizeof(paramline); - rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_SETLINECTRL, ¶mline, ulParmLen, &ulParmLen, 0, 0, 0); - if ( rc != NO_ERROR) - { - LOG_MSG ("SetLineCtrl failed with error %d.\n", rc); - } - - CSerial::Init_Registers(); - InstallationSuccessful = true; - receiveblock = false; - - // Clears comm errors - USHORT errors = 0; - ulParmLen = sizeof(errors); - DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETCOMMERROR, 0, 0, 0, &errors, ulParmLen, &ulParmLen); - setEvent(SERIAL_POLLING_EVENT, 1); - } - -CDirectSerial::~CDirectSerial () { - if (hCom != 0) - DosClose (hCom); -} - - - -/*****************************************************************************/ -/* updatePortConfig is called when emulated app changes the serial port **/ -/* parameters baudrate, stopbits, number of databits, parity. **/ -/*****************************************************************************/ -void CDirectSerial::updatePortConfig (Bit16u divider, Bit8u lcr) { - Bit8u parity = 0; - Bit8u bytelength = 0; - struct { - ULONG baud; - BYTE fraction; - } setbaud; - - // baud - if (divider <= 0x1) - setbaud.baud = 115200; - else if (divider <= 0x2) - setbaud.baud = 57600; - else if (divider <= 0x3) - setbaud.baud = 38400; - else if (divider <= 0x6) - setbaud.baud = 19200; - else if (divider <= 0xc) - setbaud.baud = 9600; - else if (divider <= 0x18) - setbaud.baud = 4800; - else if (divider <= 0x30) - setbaud.baud = 2400; - else if (divider <= 0x60) - setbaud.baud = 1200; - else if (divider <= 0xc0) - setbaud.baud = 600; - else if (divider <= 0x180) - setbaud.baud = 300; - else if (divider <= 0x417) - setbaud.baud = 110; - - // I read that windows can handle nonstandard baudrates: - else - setbaud.baud = 115200 / divider; - - - setbaud.fraction = 0; - ULONG ulParmLen = sizeof(setbaud); - APIRET rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_EXTSETBAUDRATE, &setbaud, ulParmLen, &ulParmLen, 0, 0, 0); - if (rc != NO_ERROR) - { - LOG_MSG("Serial%d: Desired serial mode not supported (Baud: %d, %d, Error: %d)", - COMNUMBER, setbaud.baud, divider, rc); - } - - - struct { - UCHAR data; - UCHAR parity; - UCHAR stop; - } paramline; - - // byte length - bytelength = lcr & 0x3; - bytelength += 5; - paramline.data = bytelength; - - // parity - parity = lcr & 0x38; - parity = parity >> 3; - switch (parity) { - case 0x1: - paramline.parity = 1; - break; - case 0x3: - paramline.parity = 2; - break; - case 0x5: - paramline.parity = 3; - break; - case 0x7: - paramline.parity = 4; - break; - default: - paramline.parity = 0; - break; - } - - // stopbits - if (lcr & 0x4) { - if (bytelength == 5) - paramline.stop = 1; - else - paramline.stop = 2; - } else { - paramline.stop = 0; - } - - -#ifdef SERIAL_DEBUG - LOG_MSG("_____________________________________________________"); - LOG_MSG("Serial%d, new baud rate: %d", COMNUMBER, setbaud.baud); - LOG_MSG("Serial%d: new bytelen: %d", COMNUMBER, paramline.data); - LOG_MSG("Serial%d: new parity: %d", COMNUMBER, paramline.parity); - LOG_MSG("Serial%d: new stopbits: %d", COMNUMBER, paramline.stop); -#endif - - ulParmLen = sizeof(paramline); - rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_SETLINECTRL, ¶mline, ulParmLen, &ulParmLen, 0, 0, 0); - if ( rc != NO_ERROR) - { -#ifdef SERIAL_DEBUG - if (dbg_modemcontrol) - { - fprintf(debugfp, "%12.3f serial mode not supported: rate=%d, LCR=%x.\r\n", PIC_FullIndex(), setbaud.baud, lcr); - } -#endif - LOG_MSG("Serial%d: Desired serial mode not supported (%d,%d,%d,%d)", - COMNUMBER, setbaud.baud, paramline.data, paramline.parity, lcr); - } - - -} - -void CDirectSerial::updateMSR () { - Bit8u newmsr = 0; - UCHAR dptr = 0; - ULONG ulParmLen = sizeof(dptr); - - APIRET rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETMODEMINPUT, 0, 0, 0, &dptr, ulParmLen, &ulParmLen); - if (rc != NO_ERROR) { - LOG_MSG ("Serial port at %x: GetModemInput failed with %d !", idnumber, dptr); - } - setCTS( (dptr & 16) != 0); - setDSR( (dptr & 32) != 0); - setRI( (dptr & 64) != 0); - setCD( (dptr & 128) != 0); -} - -void CDirectSerial::transmitByte (Bit8u val, bool first) { - ULONG bytesWritten = 0; - APIRET rc = DosWrite (hCom, &val, 1, &bytesWritten); - if (rc == NO_ERROR && bytesWritten > 0) { - //LOG_MSG("UART 0x%x: TX 0x%x", base,val); - } else { - LOG_MSG ("Serial%d: NO BYTE WRITTEN!", idnumber); - } - if (first) - { - setEvent(SERIAL_THR_EVENT, bytetime / 8); - } else { - setEvent(SERIAL_TX_EVENT, bytetime); - } -} - -/*****************************************************************************/ -/* setBreak(val) switches break on or off **/ -/*****************************************************************************/ - -void CDirectSerial::setBreak (bool value) { - USHORT error; - ULONG ulParmLen = sizeof(error); - if (value) - DosDevIOCtl (hCom, IOCTL_ASYNC, ASYNC_SETBREAKON, 0,0,0, &error, ulParmLen, &ulParmLen); - else - DosDevIOCtl (hCom, IOCTL_ASYNC, ASYNC_SETBREAKOFF, 0,0,0, &error, ulParmLen, &ulParmLen); -} - -/*****************************************************************************/ -/* updateModemControlLines(mcr) sets DTR and RTS. **/ -/*****************************************************************************/ -void CDirectSerial::setRTSDTR(bool rts, bool dtr) -{ - bool change = false; - DCBINFO dcb; - ULONG ulParmLen = sizeof(dcb); - - DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETDCBINFO, 0, 0, 0, &dcb, ulParmLen, &ulParmLen); - - /*** DTR ***/ - if (dtr) { // DTR on - if (dcb.fbCtlHndShake && 3 == 0) { // DTR disabled - dcb.fbCtlHndShake |= 1; - change = true; - } - } else { - if (dcb.fbCtlHndShake && 3 == 1) { // DTR enabled - dcb.fbCtlHndShake &= ~3; - change = true; - } - } - /*** RTS ***/ - if (rts) { // RTS on - if (dcb.fbFlowReplace && 192 == 0) { //RTS disabled - dcb.fbFlowReplace |= 64; - change = true; - } - } else { - if (dcb.fbFlowReplace && 192 == 1) { // RTS enabled - dcb.fbFlowReplace &= ~192; - change = true; - } - } - if (change) - DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcb, ulParmLen, &ulParmLen, 0, 0, 0); -} - -void CDirectSerial::setRTS(bool val) -{ - bool change = false; - DCBINFO dcb; - ULONG ulParmLen = sizeof(dcb); - - DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETDCBINFO, 0, 0, 0, &dcb, ulParmLen, &ulParmLen); - - /*** RTS ***/ - if (val) { // RTS on - if (dcb.fbFlowReplace && 192 == 0) { //RTS disabled - dcb.fbFlowReplace |= 64; - change = true; - } - } else { - if (dcb.fbFlowReplace && 192 == 1) { // RTS enabled - dcb.fbFlowReplace &= ~192; - change = true; - } - } - if (change) - DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcb, ulParmLen, &ulParmLen, 0, 0, 0); - } - -void CDirectSerial::setDTR(bool val) -{ - bool change = false; - DCBINFO dcb; - ULONG ulParmLen = sizeof(dcb); - - DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETDCBINFO, 0, 0, 0, &dcb, ulParmLen, &ulParmLen); - - /*** DTR ***/ - if (val) { // DTR on - if (dcb.fbCtlHndShake && 3 == 0) { // DTR disabled - dcb.fbCtlHndShake |= 1; - change = true; - } - } else { - if (dcb.fbCtlHndShake && 3 == 1) { // DTR enabled - dcb.fbCtlHndShake &= ~3; - change = true; - } - } - if (change) - DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcb, ulParmLen, &ulParmLen, 0, 0, 0); - } - - -void CDirectSerial::handleUpperEvent(Bit16u type) - { - switch(type) { - case SERIAL_POLLING_EVENT: { - ULONG dwRead = 0; - ULONG errors = 0; - Bit8u chRead = 0; - - setEvent(SERIAL_POLLING_EVENT, 1); - if(!receiveblock) { - if(((!(LSR&LSR_RX_DATA_READY_MASK)) || rx_retry>=rx_retry_max )) - { - rx_retry=0; - if (DosRead (hCom, &chRead, 1, &dwRead) == NO_ERROR) { - if (dwRead) { - receiveByte (chRead); - setEvent(40, bytetime-0.03f); // receive timing - receiveblock=true; - } - } - } else rx_retry++; - } - // check for errors - CheckErrors(); - // update Modem input line states - updateMSR (); - break; - } - case 40: { - // receive time is up - ULONG dwRead = 0; - Bit8u chRead = 0; - receiveblock=false; - // check if there is something to receive - if(((!(LSR&LSR_RX_DATA_READY_MASK)) || rx_retry>=rx_retry_max )) - { - rx_retry=0; - if (DosRead (hCom, &chRead, 1, &dwRead) == NO_ERROR) { - if (dwRead) { - receiveByte (chRead); - setEvent(40, bytetime-0.03f); // receive timing - receiveblock=true; - } - } - } else rx_retry++; - break; - } - case SERIAL_TX_EVENT: { - ULONG dwRead = 0; - Bit8u chRead = 0; - if(!receiveblock) { - if(((!(LSR&LSR_RX_DATA_READY_MASK)) || rx_retry>=rx_retry_max )) - { - rx_retry=0; - if (DosRead (hCom, &chRead, 1, &dwRead) == NO_ERROR) { - if (dwRead) { - receiveByte (chRead); - setEvent(40, bytetime-0.03f); // receive timing - receiveblock=true; - } - } - } else rx_retry++; - } - ByteTransmitted(); - break; - } - case SERIAL_THR_EVENT: { - ByteTransmitting(); - setEvent(SERIAL_TX_EVENT,bytetime+0.03f); - break; - } - } - -} - -void CDirectSerial::CheckErrors() { - - USHORT errors = 0, event = 0; - ULONG ulParmLen = sizeof(errors); - DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETCOMMEVENT, 0, 0, 0, &event, ulParmLen, &ulParmLen); - if (event & (64 + 128) ) { // Break (Bit 6) or Frame or Parity (Bit 7) error - Bit8u errreg = 0; - if (event & 64) errreg |= LSR_RX_BREAK_MASK; - if (event & 128) { - DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETCOMMERROR, 0, 0, 0, &errors, ulParmLen, &ulParmLen); - if (errors & 8) errreg |= LSR_FRAMING_ERROR_MASK; - if (errors & 4) errreg |= LSR_PARITY_ERROR_MASK; - } - receiveError (errreg); - } -} - -#endif -#endif diff --git a/src/hardware/serialport/directserial_os2.h b/src/hardware/serialport/directserial_os2.h deleted file mode 100644 index 5d818b27..00000000 --- a/src/hardware/serialport/directserial_os2.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2002-2009 The DOSBox Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* $Id: directserial_os2.h,v 1.5 2009-05-27 09:15:41 qbix79 Exp $ */ - -// include guard -#ifndef DOSBOX_DIRECTSERIAL_OS2_H -#define DOSBOX_DIRECTSERIAL_OS2_H - -#include "dosbox.h" - -#if C_DIRECTSERIAL -#if defined(OS2) -#define DIRECTSERIAL_AVAILIBLE -#include "serialport.h" -#define INCL_DOSFILEMGR -#define INCL_DOSERRORS -#define INCL_DOSDEVICES -#define INCL_DOSDEVIOCTL -#define INCL_DOSPROCESS -#include - -class CDirectSerial : public CSerial { -public: - HFILE hCom; - BOOL fSuccess; - - CDirectSerial(Bitu id, CommandLine* cmd); - ~CDirectSerial(); - - - //Bitu lastChance; // If there is no space for new - // received data, it gets a little chance - //Bit8u ChanceChar; - - //bool CanRecv(void); - //bool CanSend(void); - - - //void RXBufferEmpty(); - bool receiveblock; - Bitu rx_retry; - Bitu rx_retry_max; - - void CheckErrors(); - - void updatePortConfig(Bit16u divider, Bit8u lcr); - void updateMSR(); - void transmitByte(Bit8u val, bool first); - void setBreak(bool value); - - void setRTSDTR(bool rts, bool dtr); - void setRTS(bool val); - void setDTR(bool val); - void handleUpperEvent(Bit16u type); - - - //void updateModemControlLines(/*Bit8u mcr*/); - //void Timer2(void); - - -}; -#endif // IFDEF - -#endif // C_DIRECTSERIAL -#endif // include guard - diff --git a/src/hardware/serialport/directserial_posix.cpp b/src/hardware/serialport/directserial_posix.cpp deleted file mode 100644 index 64bd7c2b..00000000 --- a/src/hardware/serialport/directserial_posix.cpp +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright (C) 2002-2009 The DOSBox Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* $Id: directserial_posix.cpp,v 1.4 2009-05-27 09:15:41 qbix79 Exp $ */ - -#include "dosbox.h" - -#if C_DIRECTSERIAL - -// Posix version -#if defined (LINUX) || defined (MACOSX) || defined (BSD) - -#include "serialport.h" -#include "directserial_posix.h" -#include "pic.h" - -#include -#include -#include - -#include -#include - -/* This is a serial passthrough class. Its amazingly simple to */ -/* write now that the serial ports themselves were abstracted out */ - -CDirectSerial::CDirectSerial (Bitu id, CommandLine* cmd) - :CSerial (id, cmd) { - InstallationSuccessful = false; - - rx_retry = 0; - rx_retry_max = 0; - - std::string prefix="/dev/"; - std::string tmpstring; - if(!cmd->FindStringBegin("realport:",tmpstring,false)) return; - -#if SERIAL_DEBUG - if(dbg_modemcontrol) - fprintf(debugfp,"%12.3f Port type directserial realport %s\r\n", - PIC_FullIndex(),tmpstring.c_str()); -#endif - - prefix.append(tmpstring); - - // rxdelay: How many milliseconds to wait before causing an - // overflow when the application is unresponsive. - if(getBituSubstring("rxdelay:", &rx_retry_max, cmd)) { - if(!(rx_retry_max<=10000)) rx_retry_max=0; - } - - const char* tmpchar=prefix.c_str(); - - LOG_MSG ("Serial%d: Opening %s", COMNUMBER, tmpchar); - - fileHandle = open (tmpchar, O_RDWR | O_NOCTTY | O_NONBLOCK); - - if (fileHandle < 0) { - LOG_MSG ("Serial%d: Serial Port \"%s\" could not be opened.", - COMNUMBER, tmpchar); - if (errno == 2) { - LOG_MSG ("The specified port does not exist."); - } else if (errno == EBUSY) { - LOG_MSG ("The specified port is already in use."); - } else { - LOG_MSG ("Errno %d occurred.", errno); - } - return; - } - - int result = tcgetattr(fileHandle, &termInfo); - - - if (result==-1) { - // Handle the error. - LOG_MSG ("tcgetattr failed with error %d.\n", errno); - return; - } - - // save it here to restore in destructor - tcgetattr(fileHandle,&backup); - - // initialize the port - termInfo.c_cflag = CS8 | CREAD | CLOCAL; // noparity, 1 stopbit - termInfo.c_iflag = PARMRK | INPCK; - termInfo.c_oflag = 0; - termInfo.c_lflag = 0; - - cfsetospeed (&termInfo, B9600); - cfsetispeed (&termInfo, B9600); - - termInfo.c_cc[VMIN] = 0; - termInfo.c_cc[VTIME] = 0; - - tcflush (fileHandle, TCIFLUSH); - tcsetattr (fileHandle, TCSANOW, &termInfo); - - //initialise base class - CSerial::Init_Registers(); - InstallationSuccessful = true; - receiveblock=false; - - setEvent(SERIAL_POLLING_EVENT, 1); // millisecond tick -} - -CDirectSerial::~CDirectSerial () { - if (fileHandle >= 0) - { - tcsetattr(fileHandle, TCSANOW, &backup); - close(fileHandle); - } - // We do not use own events so we don't have to clear them. -} - -void CDirectSerial::handleUpperEvent(Bit16u type) { - - switch(type) { - case SERIAL_POLLING_EVENT: { - setEvent(SERIAL_POLLING_EVENT, 1); - if(!receiveblock) { - if(((!(LSR&LSR_RX_DATA_READY_MASK)) || rx_retry>=rx_retry_max )) - { - ReadCharacter(); - } else rx_retry++; - } - // check for errors - CheckErrors(); - // update Modem input line states - updateMSR (); - break; - } - case 40: { - // receive time is up - receiveblock=false; - // check if there is something to receive - if(((!(LSR&LSR_RX_DATA_READY_MASK)) || rx_retry>=rx_retry_max )) - { - ReadCharacter(); - } else rx_retry++; - break; - } - case SERIAL_TX_EVENT: { - if(!receiveblock) { - if(((!(LSR&LSR_RX_DATA_READY_MASK)) || rx_retry>=rx_retry_max )) - { - ReadCharacter(); - } else rx_retry++; - } - ByteTransmitted(); - break; - } - case SERIAL_THR_EVENT: { - ByteTransmitting(); - setEvent(SERIAL_TX_EVENT,bytetime+0.03f); - break; - } - } -} - -void CDirectSerial::ReadCharacter() -{ - Bit8u chRead = 0; - int dwRead = 0; - rx_retry=0; - - dwRead=read(fileHandle,&chRead,1); - if (dwRead==1) { - if(chRead==0xff) // error escape - { - dwRead=read(fileHandle,&chRead,1); - if(chRead==0x00) // an error - { - dwRead=read(fileHandle,&chRead,1); - if(chRead==0x0)receiveError(LSR_RX_BREAK_MASK); - else receiveError(LSR_PARITY_ERROR_MASK); - } - } - receiveByte (chRead); - setEvent(40, bytetime-0.03f); // receive timing - receiveblock=true; - } -} - -void CDirectSerial::CheckErrors() { - -} - -/*****************************************************************************/ -/* updatePortConfig is called when emulated app changes the serial port **/ -/* parameters baudrate, stopbits, number of databits, parity. **/ -/*****************************************************************************/ -void CDirectSerial::updatePortConfig (Bit16u divider, Bit8u lcr) { - Bit8u parity = 0; - Bit8u bytelength = 0; - int baudrate=0; - - // baud - termInfo.c_cflag = CREAD | CLOCAL; - - if (divider == 0x1) baudrate = B115200; - else if (divider == 0x2) baudrate = B57600; - else if (divider == 0x3) baudrate = B38400; - else if (divider == 0x6) baudrate = B19200; - else if (divider == 0xc) baudrate = B9600; - else if (divider == 0x18) baudrate = B4800; - else if (divider == 0x30) baudrate = B2400; - else if (divider == 0x60) baudrate = B1200; - else if (divider == 0xc0) baudrate = B600; - else if (divider == 0x180) baudrate = B300; - else if (divider == 0x417) baudrate = B110; - - // Don't think termios supports nonstandard baudrates - else baudrate = B9600; - - // byte length - bytelength = lcr & 0x3; - bytelength += 5; - - switch (bytelength) { - case 5: - termInfo.c_cflag |= CS5; - break; - - case 6: - termInfo.c_cflag |= CS6; - break; - - case 7: - termInfo.c_cflag |= CS7; - break; - - case 8: - default: - termInfo.c_cflag |= CS8; - break; - } - - // parity - parity = lcr & 0x38; - parity >>= 3; - switch (parity) { - case 0x1: - termInfo.c_cflag |= PARODD; - termInfo.c_cflag |= PARENB; - break; - case 0x3: - termInfo.c_cflag |= PARENB; - break; - case 0x5: - -// "works on many systems" -#define CMSPAR 010000000000 - - termInfo.c_cflag |= PARODD; - termInfo.c_cflag |= PARENB; - termInfo.c_cflag |= CMSPAR; - //LOG_MSG("Serial%d: Mark parity not supported.", COMNUMBER); - break; - case 0x7: - termInfo.c_cflag |= PARENB; - termInfo.c_cflag |= CMSPAR; - //LOG_MSG("Serial%d: Space parity not supported.", COMNUMBER); - break; - default: // no parity - break; - } - - // stopbits - if (lcr & 0x4) termInfo.c_cflag |= CSTOPB; - - cfsetospeed (&termInfo, baudrate); - cfsetispeed (&termInfo, baudrate); - - int retval = tcsetattr(fileHandle, TCSANOW, &termInfo); - - if(retval==-1) - LOG_MSG ("Serial%d: Desired serial mode not supported", COMNUMBER); - -} - -void CDirectSerial::updateMSR () { - long flags = 0; - ioctl (fileHandle, TIOCMGET, &flags); - - if (flags & TIOCM_CTS) setCTS(true); - else setCTS(false); - - if (flags & TIOCM_DSR) setDSR(true); - else setDSR(false); - - if (flags & TIOCM_RI) setRI(true); - else setRI(false); - - if (flags & TIOCM_CD) setCD(true); - else setCD(false); -} - -void CDirectSerial::transmitByte (Bit8u val, bool first) { - if((LCR&LCR_BREAK_MASK) == 0) { - - int bytesWritten = write(fileHandle, &val, 1); - if (bytesWritten != 1) - LOG_MSG ("Serial%d: COM port error: write failed!", idnumber); - } - if(first) setEvent(SERIAL_THR_EVENT, bytetime/8); - else setEvent(SERIAL_TX_EVENT, bytetime); -} - -/*****************************************************************************/ -/* setBreak(val) switches break on or off **/ -/*****************************************************************************/ -void CDirectSerial::setBreak (bool value) { - if (value) ioctl (fileHandle, TIOCSBRK); - else ioctl (fileHandle, TIOCCBRK); -} - -/*****************************************************************************/ -/* updateModemControlLines(mcr) sets DTR and RTS. **/ -/*****************************************************************************/ -void CDirectSerial::setRTSDTR(bool rts, bool dtr) { - - long setflags = 0; - long clearflags = 0; - - if(rts) setflags |= TIOCM_RTS; - else clearflags |= TIOCM_RTS; - - if(dtr) setflags |= TIOCM_DTR; - else clearflags |= TIOCM_DTR; - - if(setflags) ioctl (fileHandle, TIOCMBIS, &setflags); - if(clearflags) ioctl (fileHandle, TIOCMBIC, &clearflags); -} -void CDirectSerial::setRTS(bool val) { - long flag = TIOCM_RTS; - if(val) ioctl(fileHandle, TIOCMBIS, &flag); - else ioctl(fileHandle, TIOCMBIC, &flag); -} -void CDirectSerial::setDTR(bool val) { - long flag = TIOCM_DTR; - if(val) ioctl(fileHandle, TIOCMBIS, &flag); - else ioctl(fileHandle, TIOCMBIC, &flag); -} - -#endif -#endif diff --git a/src/hardware/serialport/directserial_posix.h b/src/hardware/serialport/directserial_posix.h deleted file mode 100644 index 6d9865f5..00000000 --- a/src/hardware/serialport/directserial_posix.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2002-2009 The DOSBox Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* $Id: directserial_posix.h,v 1.4 2009-05-27 09:15:41 qbix79 Exp $ */ - -// include guard -#ifndef DOSBOX_DIRECTSERIAL_POSIX_H -#define DOSBOX_DIRECTSERIAL_POSIX_H - -#include "dosbox.h" - -#if C_DIRECTSERIAL -#if defined (LINUX) || defined (MACOSX) || defined (BSD) - - - -#define DIRECTSERIAL_AVAILIBLE -#include "serialport.h" -#include -#include - -class CDirectSerial : public CSerial { -public: - termios termInfo; - termios backup; - int fileHandle; - - CDirectSerial(Bitu id, CommandLine* cmd); - ~CDirectSerial(); - bool receiveblock; // It's not a block of data it rather blocks - - Bitu rx_retry; // counter of retries - - Bitu rx_retry_max; // how many POLL_EVENTS to wait before causing - // a overrun error. - - void ReadCharacter(); - void CheckErrors(); - - void updatePortConfig(Bit16u divider, Bit8u lcr); - void updateMSR(); - void transmitByte(Bit8u val, bool first); - void setBreak(bool value); - - void setRTSDTR(bool rts, bool dtr); - void setRTS(bool val); - void setDTR(bool val); - void handleUpperEvent(Bit16u type); - -}; - -#endif // WIN32 -#endif // C_DIRECTSERIAL -#endif // include guard diff --git a/src/hardware/serialport/directserial_win32.cpp b/src/hardware/serialport/directserial_win32.cpp deleted file mode 100644 index c3073bb4..00000000 --- a/src/hardware/serialport/directserial_win32.cpp +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright (C) 2002-2009 The DOSBox Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* $Id: directserial_win32.cpp,v 1.8 2009-05-27 09:15:41 qbix79 Exp $ */ - -#include "dosbox.h" - -#if C_DIRECTSERIAL - -/* Windows version */ -#if defined (WIN32) - -#include "serialport.h" -#include "directserial_win32.h" -#include "misc_util.h" -#include "pic.h" - -// Win32 related headers -#include - -/* This is a serial passthrough class. Its amazingly simple to */ -/* write now that the serial ports themselves were abstracted out */ - -CDirectSerial::CDirectSerial (Bitu id, CommandLine* cmd) - :CSerial (id, cmd) { - InstallationSuccessful = false; - hCom = INVALID_HANDLE_VALUE; // else destructor may close an invalid handle - rx_retry = 0; - rx_retry_max = 0; - - // open the port in NT object space (recommended by Microsoft) - // allows the user to open COM10+ and custom port names. - std::string prefix="\\\\.\\"; - std::string tmpstring; - if(!cmd->FindStringBegin("realport:",tmpstring,false)) return; - -#if SERIAL_DEBUG - if(dbg_modemcontrol) - fprintf(debugfp,"%12.3f Port type directserial realport %s\r\n", - PIC_FullIndex(),tmpstring.c_str()); -#endif - - prefix.append(tmpstring); - - // rxdelay: How many milliseconds to wait before causing an - // overflow when the application is unresponsive. - if(getBituSubstring("rxdelay:", &rx_retry_max, cmd)) { - if(!(rx_retry_max<=10000)) { - rx_retry_max=0; - } - } - - const char* tmpchar=prefix.c_str(); - - LOG_MSG ("Serial%d: Opening %s", COMNUMBER, tmpstring.c_str()); - hCom = CreateFile (tmpchar, - GENERIC_READ | GENERIC_WRITE, 0, - // must be opened with exclusive-access - NULL, // no security attributes - OPEN_EXISTING, // must use OPEN_EXISTING - 0, // non overlapped I/O - NULL // hTemplate must be NULL for comm devices - ); - - if (hCom == INVALID_HANDLE_VALUE) { - int error = GetLastError (); - LOG_MSG ("Serial%d: Serial Port \"%s\" could not be opened.", - COMNUMBER, tmpstring.c_str()); - if (error == 2) { - LOG_MSG ("The specified port does not exist."); - } else if (error == 5) { - LOG_MSG ("The specified port is already in use."); - } else { - LOG_MSG ("Windows error %d occurred.", error); - } - return; - } - - dcb.DCBlength=sizeof(dcb); - fSuccess = GetCommState (hCom, &dcb); - - if (!fSuccess) { - // Handle the error. - LOG_MSG ("GetCommState failed with error %d.\n", (int)GetLastError ()); - hCom = INVALID_HANDLE_VALUE; - return; - } - - // initialize the port - dcb.BaudRate=CBR_9600; - dcb.fBinary=true; - dcb.fParity=true; - dcb.fOutxCtsFlow=false; - dcb.fOutxDsrFlow=false; - dcb.fDtrControl=DTR_CONTROL_DISABLE; - dcb.fDsrSensitivity=false; - - dcb.fOutX=false; - dcb.fInX=false; - dcb.fErrorChar=0; - dcb.fNull=false; - dcb.fRtsControl=RTS_CONTROL_DISABLE; - dcb.fAbortOnError=false; - - dcb.ByteSize=8; - dcb.Parity=NOPARITY; - dcb.StopBits=ONESTOPBIT; - - fSuccess = SetCommState (hCom, &dcb); - - if (!fSuccess) { - // Handle the error. - LOG_MSG ("SetCommState failed with error %d.\n", (int)GetLastError ()); - hCom = INVALID_HANDLE_VALUE; - return; - } - - // Configure timeouts to effectively use polling - COMMTIMEOUTS ct; - ct.ReadIntervalTimeout = MAXDWORD; - ct.ReadTotalTimeoutConstant = 0; - ct.ReadTotalTimeoutMultiplier = 0; - ct.WriteTotalTimeoutConstant = 0; - ct.WriteTotalTimeoutMultiplier = 0; - SetCommTimeouts (hCom, &ct); - - CSerial::Init_Registers(); - InstallationSuccessful = true; - receiveblock=false; - - ClearCommBreak (hCom); - setEvent(SERIAL_POLLING_EVENT, 1); // millisecond tick -} - -CDirectSerial::~CDirectSerial () { - if (hCom != INVALID_HANDLE_VALUE) CloseHandle (hCom); - // We do not use own events so we don't have to clear them. -} - -void CDirectSerial::handleUpperEvent(Bit16u type) { - - switch(type) { - case SERIAL_POLLING_EVENT: { - DWORD dwRead = 0; - Bit8u chRead = 0; - - setEvent(SERIAL_POLLING_EVENT, 1); - if(!receiveblock) { - if(((!(LSR&LSR_RX_DATA_READY_MASK)) || rx_retry>=rx_retry_max )) - { - rx_retry=0; - if (ReadFile (hCom, &chRead, 1, &dwRead, NULL)) { - if (dwRead) { - receiveByte (chRead); - setEvent(40, bytetime-0.03f); // receive timing - receiveblock=true; - } - } - } else rx_retry++; - } - // check for errors - CheckErrors(); - // update Modem input line states - updateMSR (); - break; - } - case 40: { - // receive time is up - DWORD dwRead = 0; - Bit8u chRead = 0; - receiveblock=false; - // check if there is something to receive - if(((!(LSR&LSR_RX_DATA_READY_MASK)) || rx_retry>=rx_retry_max )) - { - rx_retry=0; - if (ReadFile (hCom, &chRead, 1, &dwRead, NULL)) { - if (dwRead) { - receiveByte (chRead); - setEvent(40, bytetime-0.03f); // receive timing - receiveblock=true; - } - } - } else rx_retry++; - break; - } - case SERIAL_TX_EVENT: { - DWORD dwRead = 0; - Bit8u chRead = 0; - if(!receiveblock) { - if(((!(LSR&LSR_RX_DATA_READY_MASK)) || rx_retry>=rx_retry_max )) - { - rx_retry=0; - if (ReadFile (hCom, &chRead, 1, &dwRead, NULL)) { - if (dwRead) { - receiveByte (chRead); - setEvent(40, bytetime-0.03f); // receive timing - receiveblock=true; - } - } - } else rx_retry++; - } - ByteTransmitted(); - break; - } - case SERIAL_THR_EVENT: { - ByteTransmitting(); - setEvent(SERIAL_TX_EVENT,bytetime+0.03f); - break; - } - } -} - -void CDirectSerial::CheckErrors() { - - DWORD errors=0; - // check for errors - if (ClearCommError (hCom, &errors, NULL)) - if (errors & (CE_BREAK | CE_FRAME | CE_RXPARITY)) { - Bit8u errreg = 0; - if (errors & CE_BREAK) errreg |= LSR_RX_BREAK_MASK; - if (errors & CE_FRAME) errreg |= LSR_FRAMING_ERROR_MASK; - if (errors & CE_RXPARITY) errreg |= LSR_PARITY_ERROR_MASK; - receiveError (errreg); - } -} - -/*****************************************************************************/ -/* updatePortConfig is called when emulated app changes the serial port **/ -/* parameters baudrate, stopbits, number of databits, parity. **/ -/*****************************************************************************/ -void CDirectSerial::updatePortConfig (Bit16u divider, Bit8u lcr) { - Bit8u parity = 0; - Bit8u bytelength = 0; - - // baud - if (divider == 0x1) - dcb.BaudRate = CBR_115200; - else if (divider == 0x2) - dcb.BaudRate = CBR_57600; - else if (divider == 0x3) - dcb.BaudRate = CBR_38400; - else if (divider == 0x6) - dcb.BaudRate = CBR_19200; - else if (divider == 0xc) - dcb.BaudRate = CBR_9600; - else if (divider == 0x18) - dcb.BaudRate = CBR_4800; - else if (divider == 0x30) - dcb.BaudRate = CBR_2400; - else if (divider == 0x60) - dcb.BaudRate = CBR_1200; - else if (divider == 0xc0) - dcb.BaudRate = CBR_600; - else if (divider == 0x180) - dcb.BaudRate = CBR_300; - else if (divider == 0x417) - dcb.BaudRate = CBR_110; - - // I read that windows can handle nonstandard baudrates: - else - dcb.BaudRate = 115200 / divider; - - // byte length - bytelength = lcr & 0x3; - bytelength += 5; - dcb.ByteSize = bytelength; - - // parity - parity = lcr & 0x38; - parity = parity >> 3; - switch (parity) { - case 0x1: - dcb.Parity = ODDPARITY; - break; - case 0x3: - dcb.Parity = EVENPARITY; - break; - case 0x5: - dcb.Parity = MARKPARITY; - break; - case 0x7: - dcb.Parity = SPACEPARITY; - break; - default: - dcb.Parity = NOPARITY; - break; - } - - // stopbits - if (lcr & 0x4) { - if (bytelength == 5) - dcb.StopBits = ONE5STOPBITS; - else - dcb.StopBits = TWOSTOPBITS; - } else { - dcb.StopBits = ONESTOPBIT; - } - -#ifdef SERIALPORT_DEBUGMSG - LOG_MSG ("__________________________"); - LOG_MSG ("Serial%d: new baud rate: %d", COMNUMBER, dcb.BaudRate); - LOG_MSG ("Serial%d: new bytelen: %d", COMNUMBER, dcb.ByteSize); - LOG_MSG ("Serial%d: new parity: %d", COMNUMBER, dcb.Parity); - LOG_MSG ("Serial%d: new stopbits: %d", COMNUMBER, dcb.StopBits); -#endif - - if (!SetCommState (hCom, &dcb)) { - -#if SERIAL_DEBUG - if(dbg_modemcontrol) - fprintf(debugfp,"%12.3f serial mode not supported: rate=%d,LCR=%x.\r\n", - PIC_FullIndex(),dcb.BaudRate,lcr); -#endif - - LOG_MSG ("Serial%d: Desired serial mode not supported (%d,%d,%d,%d", - (Bit32u)dcb.BaudRate,(Bit32u)dcb.ByteSize, - (Bit32u)dcb.Parity,(Bit32u)dcb.StopBits, COMNUMBER); - } -} - -void CDirectSerial::updateMSR () { - DWORD dptr = 0; - - if (!GetCommModemStatus (hCom, &dptr)) { -#ifdef SERIALPORT_DEBUGMSG -// LOG_MSG ("Serial port at %x: GetCommModemStatus failed!", base); -#endif - //return; - } - setCTS((dptr & MS_CTS_ON)!=0); - setDSR((dptr & MS_DSR_ON)!=0); - setRI ((dptr & MS_RING_ON)!=0); - setCD((dptr & MS_RLSD_ON)!=0); -} - -void CDirectSerial::transmitByte (Bit8u val, bool first) { - // mean bug: with break = 1, WriteFile will never return. - if((LCR&LCR_BREAK_MASK) == 0) { - DWORD bytesWritten = 0; - WriteFile (hCom, &val, 1, &bytesWritten, NULL); - if (bytesWritten != 1) - LOG_MSG ("Serial%d: COM port error: write failed!", idnumber); - } - if(first) setEvent(SERIAL_THR_EVENT, bytetime/8); - else setEvent(SERIAL_TX_EVENT, bytetime); -} - -/*****************************************************************************/ -/* setBreak(val) switches break on or off **/ -/*****************************************************************************/ -void CDirectSerial::setBreak (bool value) { - if (value) SetCommBreak (hCom); - else ClearCommBreak (hCom); -} - -/*****************************************************************************/ -/* updateModemControlLines(mcr) sets DTR and RTS. **/ -/*****************************************************************************/ -void CDirectSerial::setRTSDTR(bool rts, bool dtr) { - if(rts) dcb.fRtsControl = RTS_CONTROL_ENABLE; - else dcb.fRtsControl = RTS_CONTROL_DISABLE; - if(dtr) dcb.fDtrControl = DTR_CONTROL_ENABLE; - else dcb.fDtrControl = DTR_CONTROL_DISABLE; - SetCommState (hCom, &dcb); - -} -void CDirectSerial::setRTS(bool val) { - if(val) dcb.fRtsControl = RTS_CONTROL_ENABLE; - else dcb.fRtsControl = RTS_CONTROL_DISABLE; - SetCommState (hCom, &dcb); -} -void CDirectSerial::setDTR(bool val) { - if(val) dcb.fDtrControl = DTR_CONTROL_ENABLE; - else dcb.fDtrControl = DTR_CONTROL_DISABLE; - SetCommState (hCom, &dcb); -} - -#endif -#endif diff --git a/src/hardware/serialport/libserial.cpp b/src/hardware/serialport/libserial.cpp new file mode 100644 index 00000000..7ce82163 --- /dev/null +++ b/src/hardware/serialport/libserial.cpp @@ -0,0 +1,706 @@ +/* + * Copyright (C) 2002-2007 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: libserial.cpp,v 1.1 2009-09-25 23:40:47 h-a-l-9000 Exp $ */ + +#include "libserial.h" + +#include "config.h" + +#ifdef WIN32 + +#include +#include + +struct _COMPORT { + HANDLE porthandle; + bool breakstatus; + DCB orig_dcb; +}; + +bool SERIAL_open(const char* portname, COMPORT* port) { + // allocate COMPORT structure + COMPORT cp = (_COMPORT*)malloc(sizeof(_COMPORT)); + if(cp == NULL) return false; + + cp->breakstatus=false; + + // open the port in NT object space (recommended by Microsoft) + // allows the user to open COM10+ and custom port names. + int len = strlen(portname); + if(len > 240) { + SetLastError(ERROR_BUFFER_OVERFLOW); + return false; + } + char extended_portname[256] = "\\\\.\\"; + memcpy(extended_portname+4,portname,len+1); + + cp->porthandle = CreateFile (extended_portname, + GENERIC_READ | GENERIC_WRITE, 0, + // must be opened with exclusive-access + NULL, // no security attributes + OPEN_EXISTING, // must use OPEN_EXISTING + 0, // non overlapped I/O + NULL // hTemplate must be NULL for comm devices + ); + + if (cp->porthandle == INVALID_HANDLE_VALUE) goto cleanup_error; + + cp->orig_dcb.DCBlength=sizeof(DCB); + + if(!GetCommState(cp->porthandle, &cp->orig_dcb)) { + goto cleanup_error; + } + + // configure the port for polling + DCB newdcb; + memcpy(&newdcb,&cp->orig_dcb,sizeof(DCB)); + + newdcb.fBinary=true; + newdcb.fParity=true; + newdcb.fOutxCtsFlow=false; + newdcb.fOutxDsrFlow=false; + newdcb.fDtrControl=DTR_CONTROL_DISABLE; + newdcb.fDsrSensitivity=false; + + newdcb.fOutX=false; + newdcb.fInX=false; + newdcb.fErrorChar=0; + newdcb.fNull=false; + newdcb.fRtsControl=RTS_CONTROL_DISABLE; + newdcb.fAbortOnError=false; + + if(!SetCommState(cp->porthandle, &newdcb)) { + goto cleanup_error; + } + + // Configure timeouts to effectively use polling + COMMTIMEOUTS ct; + ct.ReadIntervalTimeout = MAXDWORD; + ct.ReadTotalTimeoutConstant = 0; + ct.ReadTotalTimeoutMultiplier = 0; + ct.WriteTotalTimeoutConstant = 0; + ct.WriteTotalTimeoutMultiplier = 0; + if(!SetCommTimeouts(cp->porthandle, &ct)) { + goto cleanup_error; + } + if(!ClearCommBreak(cp->porthandle)) { + // Bluetooth Bluesoleil seems to not implement it + //goto cleanup_error; + } + DWORD errors; + if(!ClearCommError(cp->porthandle, &errors, NULL)) { + goto cleanup_error; + } + *port = cp; + return true; + +cleanup_error: + if (cp->porthandle != INVALID_HANDLE_VALUE) CloseHandle(cp->porthandle); + free(cp); + return false; +} + +void SERIAL_close(COMPORT port) { + // restore original DCB, close handle, free the COMPORT struct + if (port->porthandle != INVALID_HANDLE_VALUE) { + SetCommState(port->porthandle, &port->orig_dcb); + CloseHandle(port->porthandle); + } + free(port); +} + +void SERIAL_getErrorString(char* buffer, int length) { + int error = GetLastError(); + if(length < 50) return; + memset(buffer,0,length); + // get the error message text from the operating system + LPVOID sysmessagebuffer; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &sysmessagebuffer, + 0,NULL); + + const char* err5text = "The specified port is already in use.\n"; + const char* err2text = "The specified port does not exist.\n"; + + int sysmsg_offset = 0; + + if(error == 5) { + sysmsg_offset = strlen(err5text); + memcpy(buffer,err5text,sysmsg_offset); + + } else if(error == 2) { + sysmsg_offset = strlen(err2text); + memcpy(buffer,err2text,sysmsg_offset); + } + + if((length - sysmsg_offset - strlen((const char*)sysmessagebuffer)) >= 0) + memcpy(buffer + sysmsg_offset, sysmessagebuffer, + strlen((const char*)sysmessagebuffer)); + + LocalFree(sysmessagebuffer); +} + + +void SERIAL_setDTR(COMPORT port, bool value) { + EscapeCommFunction(port->porthandle, value ? SETDTR:CLRDTR); +} + +void SERIAL_setRTS(COMPORT port, bool value) { + EscapeCommFunction(port->porthandle, value ? SETRTS:CLRRTS); +} + +void SERIAL_setBREAK(COMPORT port, bool value) { + EscapeCommFunction(port->porthandle, value ? SETBREAK:CLRBREAK); + port->breakstatus = value; +} + +int SERIAL_getmodemstatus(COMPORT port) { + DWORD retval = 0; + GetCommModemStatus (port->porthandle, &retval); + return (int)retval; +} + +bool SERIAL_sendchar(COMPORT port, char data) { + DWORD bytesWritten; + + // mean bug: with break = 1, WriteFile will never return. + if(port->breakstatus) return true; // true or false?! + + WriteFile (port->porthandle, &data, 1, &bytesWritten, NULL); + if(bytesWritten==1) return true; + else return false; +} + +// 0-7 char data, higher=flags +int SERIAL_getextchar(COMPORT port) { + DWORD errors = 0; // errors from API + DWORD dwRead = 0; // Number of chars read + char chRead; + + int retval = 0; + // receive a byte; TODO communicate faliure + if (ReadFile (port->porthandle, &chRead, 1, &dwRead, NULL)) { + if (dwRead) { + // check for errors + ClearCommError(port->porthandle, &errors, NULL); + // mask bits are identical + errors &= CE_BREAK|CE_FRAME|CE_RXPARITY|CE_OVERRUN; + retval |= (errors<<8); + retval |= (chRead & 0xff); + retval |= 0x10000; + } + } + return retval; +} + +bool SERIAL_setCommParameters(COMPORT port, + int baudrate, char parity, int stopbits, int length) { + + DCB dcb; + dcb.DCBlength=sizeof(dcb); + GetCommState(port->porthandle,&dcb); + + // parity + switch (parity) { + case 'n': dcb.Parity = NOPARITY; break; + case 'o': dcb.Parity = ODDPARITY; break; + case 'e': dcb.Parity = EVENPARITY; break; + case 'm': dcb.Parity = MARKPARITY; break; + case 's': dcb.Parity = SPACEPARITY; break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // stopbits + switch(stopbits) { + case SERIAL_1STOP: dcb.StopBits = ONESTOPBIT; break; + case SERIAL_2STOP: dcb.StopBits = TWOSTOPBITS; break; + case SERIAL_15STOP: dcb.StopBits = ONE5STOPBITS; break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // byte length + if(length > 8 || length < 5) { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + dcb.ByteSize = length; + dcb.BaudRate = baudrate; + + if (!SetCommState (port->porthandle, &dcb)) return false; + return true; +} +#endif + +#if defined (LINUX) || defined (MACOSX) + +#include // strlen +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include // sprinf + +struct _COMPORT { + int porthandle; + bool breakstatus; + termios backup; +}; + +bool SERIAL_open(const char* portname, COMPORT* port) { + int result; + // allocate COMPORT structure + COMPORT cp = (_COMPORT*)malloc(sizeof(_COMPORT)); + if(cp == NULL) return false; + + cp->breakstatus=false; + + int len = strlen(portname); + if(len > 240) { + ///////////////////////////////////SetLastError(ERROR_BUFFER_OVERFLOW); + return false; + } + char extended_portname[256] = "/dev/"; + memcpy(extended_portname+5,portname,len); + + cp->porthandle = open (extended_portname, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (cp->porthandle < 0) goto cleanup_error; + + result = tcgetattr(cp->porthandle,&cp->backup); + if (result==-1) goto cleanup_error; + + // get port settings + termios termInfo; + memcpy(&termInfo,&cp->backup,sizeof(termios)); + + // initialize the port + termInfo.c_cflag = CS8 | CREAD | CLOCAL; // noparity, 1 stopbit + termInfo.c_iflag = PARMRK | INPCK; + termInfo.c_oflag = 0; + termInfo.c_lflag = 0; + termInfo.c_cc[VMIN] = 0; + termInfo.c_cc[VTIME] = 0; + + tcflush (cp->porthandle, TCIFLUSH); + tcsetattr (cp->porthandle, TCSANOW, &termInfo); + + *port = cp; + return true; + +cleanup_error: + if (cp->porthandle != 0) close(cp->porthandle); + free(cp); + return false; +} + +void SERIAL_close(COMPORT port) { + // restore original termios, close handle, free the COMPORT struct + if (port->porthandle >= 0) { + tcsetattr(port->porthandle, TCSANOW, &port->backup); + close(port->porthandle); + } + free(port); +} + +void SERIAL_getErrorString(char* buffer, int length) { + int error = errno; + if(length < 50) return; + memset(buffer,0,length); + // get the error message text from the operating system + // TODO (or not) + + const char* err5text = "The specified port is already in use.\n"; + const char* err2text = "The specified port does not exist.\n"; + + int sysmsg_offset = 0; + + if(error == EBUSY) { + sysmsg_offset = strlen(err5text); + memcpy(buffer,err5text,sysmsg_offset); + + } else if(error == 2) { + sysmsg_offset = strlen(err2text); + memcpy(buffer,err2text,sysmsg_offset); + } + + sprintf(buffer + sysmsg_offset, "System error %d.",error); + +} + +int SERIAL_getmodemstatus(COMPORT port) { + long flags = 0; + ioctl (port->porthandle, TIOCMGET, &flags); + int retval = 0; + if (flags & TIOCM_CTS) retval |= SERIAL_CTS; + if (flags & TIOCM_DSR) retval |= SERIAL_DSR; + if (flags & TIOCM_RI) retval |= SERIAL_RI; + if (flags & TIOCM_CD) retval |= SERIAL_CD; + return retval; +} + +bool SERIAL_sendchar(COMPORT port, char data) { + if(port->breakstatus) return true; // true or false?!; Does POSIX need this check? + int bytesWritten = write(port->porthandle, &data, 1); + if(bytesWritten==1) return true; + else return false; +} + +int SERIAL_getextchar(COMPORT port) { + unsigned char chRead = 0; + int dwRead = 0; + unsigned char error = 0; + int retval = 0; + + dwRead=read(port->porthandle,&chRead,1); + if (dwRead==1) { + if(chRead==0xff) // error escape + { + dwRead=read(port->porthandle,&chRead,1); + if(chRead==0x00) // an error + { + dwRead=read(port->porthandle,&chRead,1); + if(chRead==0x0) error=SERIAL_BREAK_ERR; + else error=SERIAL_FRAMING_ERR; + } + } + retval |= (error<<8); + retval |= chRead; + retval |= 0x10000; + } + return retval; +} + +bool SERIAL_setCommParameters(COMPORT port, + int baudrate, char parity, int stopbits, int length) { + + termios termInfo; + int result = tcgetattr(port->porthandle, &termInfo); + if (result==-1) return false; + termInfo.c_cflag = CREAD | CLOCAL; + + // parity + // "works on many systems" + #define CMSPAR 010000000000 + switch (parity) { + case 'n': break; + case 'o': termInfo.c_cflag |= (PARODD | PARENB); break; + case 'e': termInfo.c_cflag |= PARENB; break; + case 'm': termInfo.c_cflag |= (PARENB | CMSPAR | PARODD); break; + case 's': termInfo.c_cflag |= (PARENB | CMSPAR); break; + default: + return false; + } + // stopbits + switch(stopbits) { + case SERIAL_1STOP: break; + case SERIAL_2STOP: + case SERIAL_15STOP: termInfo.c_cflag |= CSTOPB; break; + default: + return false; + } + // byte length + if(length > 8 || length < 5) return false; + switch (length) { + case 5: termInfo.c_cflag |= CS5; break; + case 6: termInfo.c_cflag |= CS6; break; + case 7: termInfo.c_cflag |= CS7; break; + case 8: termInfo.c_cflag |= CS8; break; + } + // baudrate + int posix_baudrate=0; + switch(baudrate) { + case 115200: posix_baudrate = B115200; break; + case 57600: posix_baudrate = B57600; break; + case 38400: posix_baudrate = B38400; break; + case 19200: posix_baudrate = B19200; break; + case 9600: posix_baudrate = B9600; break; + case 4800: posix_baudrate = B4800; break; + case 2400: posix_baudrate = B2400; break; + case 1200: posix_baudrate = B1200; break; + case 600: posix_baudrate = B600; break; + case 300: posix_baudrate = B300; break; + case 110: posix_baudrate = B110; break; + default: return false; + } + cfsetospeed (&termInfo, posix_baudrate); + cfsetispeed (&termInfo, posix_baudrate); + + int retval = tcsetattr(port->porthandle, TCSANOW, &termInfo); + if(retval==-1) return false; + return true; +} + +void SERIAL_setBREAK(COMPORT port, bool value) { + ioctl(port->porthandle, value?TIOCSBRK:TIOCCBRK); +} + +void SERIAL_setDTR(COMPORT port, bool value) { + long flag = TIOCM_DTR; + ioctl(port->porthandle, value?TIOCMBIS:TIOCMBIC, &flag); +} + +void SERIAL_setRTS(COMPORT port, bool value) { + long flag = TIOCM_RTS; + ioctl(port->porthandle, value?TIOCMBIS:TIOCMBIC, &flag); +} +#endif + +#ifdef OS2 +// OS/2 related headers +#define INCL_DOSFILEMGR +#define INCL_DOSERRORS +#define INCL_DOSDEVICES +#define INCL_DOSDEVIOCTL +#define INCL_DOSPROCESS +#include + +struct _COMPORT { + HFILE porthandle; + bool breakstatus; + DCBINFO backup; +}; +// TODO: THIS IS INCOMPLETE and UNTESTED. + +bool SERIAL_open(const char* portname, COMPORT* port) { + // allocate COMPORT structure + COMPORT cp = (_COMPORT*)malloc(sizeof(_COMPORT)); + if(cp == NULL) return false; + cp->porthandle=0; + cp->breakstatus=false; + + ULONG ulAction = 0; + APIRET rc = DosOpen(portname, &cp->porthandle, + &ulAction, 0L, FILE_NORMAL, FILE_OPEN, + OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE | OPEN_FLAGS_SEQUENTIAL, 0L); + if (rc != NO_ERROR) { + goto cleanup_error; + } + + ULONG ulParmLen = sizeof(DCBINFO); + rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETDCBINFO, + 0, 0, 0, &cp->orig_dcb, ulParmLen, &ulParmLen); + if ( rc != NO_ERROR) { + goto cleanup_error; + } + // configure the port for polling + DCBINFO newdcb; + memcpy(&newdcb,&cp->orig_dcb,sizeof(DCBINFO)); + + newdcb.usWriteTimeout = 0; + newdcb.usReadTimeout = 0; //65535; + newdcb.fbCtlHndShake = dcb.fbFlowReplace = 0; + newdcb.fbTimeout = 6; + + rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_SETDCBINFO, + &newdcb, ulParmLen, &ulParmLen, 0, 0, 0); + if ( rc != NO_ERROR) { + goto cleanup_error; + } + + USHORT errors = 0; + ulParmLen = sizeof(errors); + rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETCOMMERROR, + 0, 0, 0, &errors, ulParmLen, &ulParmLen); + if ( rc != NO_ERROR) { + goto cleanup_error; + } + + *port = cp; + return true; + +cleanup_error: + // TODO error string - rc value + if (cp->porthandle != 0) CloseHandle(cp->porthandle); + free(cp); + return false; +} + +void SERIAL_getErrorString(char* buffer, int length) { + sprintf(buffer, "TODO: error handling is not fun"); +} +void SERIAL_close(COMPORT port) { + ULONG ulParmLen = sizeof(DCBINFO); + // restore original DCB, close handle, free the COMPORT struct + if (port->porthandle != 0) { + DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_SETDCBINFO, + &port->orig_dcb, ulParmLen, &ulParmLen, 0, 0, 0); + SetCmmState(port->porthandle, &port->orig_dcb); + DosClose (port->porthandle); + } + free(port); +} +bool SERIAL_sendchar(COMPORT port, char data) { + ULONG bytesWritten = 0; + if(port->breakstatus) return true; // does OS/2 need this? + + APIRET rc = DosWrite(port->porthandle, &data, 1, &bytesWritten); + if (rc == NO_ERROR && bytesWritten > 0) return true; + else return false; +} + +void SERIAL_setBREAK(COMPORT port, bool value) { + USHORT error; + ULONG ulParmLen = sizeof(error); + DosDevIOCtl(port->porthandle, IOCTL_ASYNC, + value? ASYNC_SETBREAKON:ASYNC_SETBREAKOFF, + 0,0,0, &error, ulParmLen, &ulParmLen); +} + +int SERIAL_getextchar(COMPORT port) { + ULONG dwRead = 0; // Number of chars read + char chRead; + + int retval = 0; + // receive a byte; TODO communicate faliure + if (DosRead(port->porthandle, &chRead, 1, &dwRead) == NO_ERROR) { + if (dwRead) { + // check for errors; will OS/2 clear the error on reading its data? + // if yes then this is in wrong order + USHORT errors = 0, event = 0; + ULONG ulParmLen = sizeof(errors); + DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_GETCOMMEVENT, + 0, 0, 0, &event, ulParmLen, &ulParmLen); + if (event & (64 + 128) ) { // Break (Bit 6) or Frame or Parity (Bit 7) error + Bit8u errreg = 0; + if (event & 64) retval |= SERIAL_BREAK_ERR; + if (event & 128) { + DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_GETCOMMERROR, + 0, 0, 0, &errors, ulParmLen, &ulParmLen); + if (errors & 8) retval |= SERIAL_FRAMING_ERR; + if (errors & 4) retval |= SERIAL_PARITY_ERR; + } + } + retval |= (chRead & 0xff); + retval |= 0x10000; + } + } + return retval; +} + + +int SERIAL_getmodemstatus(COMPORT port) { + UCHAR dptr = 0; + ULONG ulParmLen = sizeof(dptr); + DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_GETMODEMINPUT, + 0, 0, 0, &dptr, ulParmLen, &ulParmLen); + // bits are the same as return value + return (int)dptr; +} +void SERIAL_setDTR(COMPORT port, bool value) { + UCHAR masks[2]; + ULONG ulParmLen = sizeof(masks); + if(value) { + masks[0]=0x01; + masks[1]=0xFF; + } else { + masks[0]=0x00; + masks[1]=0xFE; + } + DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_SETMODEMCTRL, + 0,0,0, &masks, ulParmLen, &ulParmLen); +} + +void SERIAL_setRTS(COMPORT port, bool value) { + UCHAR masks[2]; + ULONG ulParmLen = sizeof(masks); + if(value) { + masks[0]=0x02; + masks[1]=0xFF; + } else { + masks[0]=0x00; + masks[1]=0xFD; + } + DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_SETMODEMCTRL, + 0,0,0, &masks, ulParmLen, &ulParmLen); +} + + + +bool SERIAL_setCommParameters(COMPORT port, + int baudrate, char parity, int stopbits, int length) { + // baud + struct { + ULONG baud; + BYTE fraction; + } setbaud; + + setbaud.baud = baudrate; + setbaud.fraction = 0; + ULONG ulParmLen = sizeof(setbaud); + APIRET rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_EXTSETBAUDRATE, + &setbaud, ulParmLen, &ulParmLen, 0, 0, 0); + if (rc != NO_ERROR) { + return false; + } + + struct { + UCHAR data; + UCHAR parity; + UCHAR stop; + } paramline; + + // byte length + if(length > 8 || length < 5) { + // TODO SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + paramline.data = length; + + // parity + switch (parity) { + case 'n': paramline.parity = 0; break; + case 'o': paramline.parity = 1; break; + case 'e': paramline.parity = 2; break; + case 'm': paramline.parity = 3; break; + case 's': paramline.parity = 4; break; + default: + // TODO SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + // stopbits + switch(stopbits) { + case SERIAL_1STOP: paramline.stop = 0; break; + case SERIAL_2STOP: paramline.stop = 2; break; + case SERIAL_15STOP: paramline.stop = 1; break; + default: + // TODO SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + // set it + ulParmLen = sizeof(paramline); + rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_SETLINECTRL, + ¶mline, ulParmLen, &ulParmLen, 0, 0, 0); + if ( rc != NO_ERROR) + return false; + return true; +} +#endif diff --git a/src/hardware/serialport/libserial.h b/src/hardware/serialport/libserial.h new file mode 100644 index 00000000..25981a49 --- /dev/null +++ b/src/hardware/serialport/libserial.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2002-2007 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: libserial.h,v 1.1 2009-09-25 23:40:47 h-a-l-9000 Exp $ */ + +typedef struct _COMPORT *COMPORT; + +bool SERIAL_open(const char* portname, COMPORT* port); +void SERIAL_close(COMPORT port); +void SERIAL_getErrorString(char* buffer, int length); + +#define SERIAL_1STOP 1 +#define SERIAL_2STOP 2 +#define SERIAL_15STOP 0 + +// parity: n, o, e, m, s + +bool SERIAL_setCommParameters(COMPORT port, + int baudrate, char parity, int stopbits, int length); + +void SERIAL_setDTR(COMPORT port, bool value); +void SERIAL_setRTS(COMPORT port, bool value); +void SERIAL_setBREAK(COMPORT port, bool value); + +#define SERIAL_CTS 0x10 +#define SERIAL_DSR 0x20 +#define SERIAL_RI 0x40 +#define SERIAL_CD 0x80 + +int SERIAL_getmodemstatus(COMPORT port); +bool SERIAL_setmodemcontrol(COMPORT port, int flags); + +bool SERIAL_sendchar(COMPORT port, char data); + +// 0-7 char data, higher=flags +#define SERIAL_BREAK_ERR 0x10 +#define SERIAL_FRAMING_ERR 0x08 +#define SERIAL_PARITY_ERR 0x04 +#define SERIAL_OVERRUN_ERR 0x02 + +int SERIAL_getextchar(COMPORT port); diff --git a/src/hardware/serialport/misc_util.cpp b/src/hardware/serialport/misc_util.cpp index 9968cd9b..6ba488d5 100644 --- a/src/hardware/serialport/misc_util.cpp +++ b/src/hardware/serialport/misc_util.cpp @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2002-2009 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id $ */ + + #include "config.h" #if C_MODEM diff --git a/src/hardware/serialport/misc_util.h b/src/hardware/serialport/misc_util.h index 08a36123..e4260422 100644 --- a/src/hardware/serialport/misc_util.h +++ b/src/hardware/serialport/misc_util.h @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2002-2009 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: misc_util.h,v 1.5 2009-09-25 23:40:47 h-a-l-9000 Exp $ */ + #ifndef SDLNETWRAPPER_H #define SDLNETWRAPPER_H diff --git a/src/hardware/serialport/nullmodem.cpp b/src/hardware/serialport/nullmodem.cpp index c447ad29..605d3826 100644 --- a/src/hardware/serialport/nullmodem.cpp +++ b/src/hardware/serialport/nullmodem.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: nullmodem.cpp,v 1.7 2009-05-27 09:15:41 qbix79 Exp $ */ +/* $Id: nullmodem.cpp,v 1.8 2009-09-25 23:40:47 h-a-l-9000 Exp $ */ #include "dosbox.h" @@ -36,7 +36,8 @@ CNullModem::CNullModem(Bitu id, CommandLine* cmd):CSerial (id, cmd) { clientport = 0; rx_retry = 0; - rx_retry_max = 100; + rx_retry_max = 20; + rx_state=N_RX_DISC; tx_gather = 12; @@ -51,7 +52,7 @@ CNullModem::CNullModem(Bitu id, CommandLine* cmd):CSerial (id, cmd) { // usedtr: The nullmodem will // 1) when it is client connect to the server not immediately but // as soon as a modem-aware application is started (DTR is switched on). - // 2) only transfer data when DTR is on. + // 2) only receive data when DTR is on. if(getBituSubstring("usedtr:", &bool_temp, cmd)) { if(bool_temp==1) { dtrrespect=true; @@ -105,6 +106,9 @@ CNullModem::CNullModem(Bitu id, CommandLine* cmd):CSerial (id, cmd) { clientsocket = new TCPClientSocket(sock); if(!clientsocket->isopen) { LOG_MSG("Serial%d: Connection failed.",COMNUMBER); +#if SERIAL_DEBUG + log_ser(dbg_aux,"Nullmodem: Connection failed."); +#endif delete clientsocket; clientsocket=0; return; @@ -115,6 +119,9 @@ CNullModem::CNullModem(Bitu id, CommandLine* cmd):CSerial (id, cmd) { if(!transparent) setRTSDTR(getRTS(), getDTR()); LOG_MSG("Serial%d: Connected to %s",COMNUMBER,peernamebuf); +#if SERIAL_DEBUG + log_ser(dbg_aux,"Nullmodem: Connected to %s",peernamebuf); +#endif setEvent(SERIAL_POLLING_EVENT, 1); CSerial::Init_Registers (); @@ -204,7 +211,7 @@ Bits CNullModem::readChar() { if(rxchar==0xff) return rxchar; // 0xff 0xff -> 0xff was meant rxchar&0x1? setCTS(true) : setCTS(false); rxchar&0x2? setDSR(true) : setDSR(false); - if(rxchar&0x4) receiveError(0x10); + if(rxchar&0x4) receiveByteEx(0x0,0x10); return -1; // no "payload" received } else return rxchar; } @@ -223,14 +230,16 @@ void CNullModem::ClientConnect(){ clientsocket->GetRemoteAddressString(peernamebuf); // transmit the line status if(!transparent) setRTSDTR(getRTS(), getDTR()); - + rx_state=N_RX_IDLE; LOG_MSG("Serial%d: Connected to %s",idnumber+1,peernamebuf); setEvent(SERIAL_POLLING_EVENT, 1); } void CNullModem::Disconnect() { + removeEvent(SERIAL_POLLING_EVENT); + removeEvent(SERIAL_RX_EVENT); // it was disconnected; free the socket and restart the server socket - LOG_MSG("Serial%d: Disconnected.",idnumber+1); + LOG_MSG("Serial%d: Disconnected.",COMNUMBER); delete clientsocket; clientsocket=0; setDSR(false); @@ -249,48 +258,115 @@ void CNullModem::handleUpperEvent(Bit16u type) { case SERIAL_POLLING_EVENT: { // periodically check if new data arrived, disconnect // if required. Add it back. - if(!receiveblock && clientsocket) { - if(((!(LSR&LSR_RX_DATA_READY_MASK)) || rx_retry>=rx_retry_max ) - &&(!dtrrespect | (dtrrespect&& getDTR()) )) { - rx_retry=0; - Bits rxchar = readChar(); - if(rxchar>=0) { - receiveblock=true; - setEvent(SERIAL_RX_EVENT, bytetime-0.01f); - receiveByte((Bit8u)rxchar); + setEvent(SERIAL_POLLING_EVENT, 1.0f); + // update Modem input line states + updateMSR(); + switch(rx_state) { + case N_RX_IDLE: + if(CanReceiveByte()) { + if(doReceive()) { + // a byte was received + rx_state=N_RX_WAIT; + setEvent(SERIAL_RX_EVENT, bytetime*0.9f); + } // else still idle + } else { +#if SERIAL_DEBUG + log_ser(dbg_aux,"Nullmodem: block on polling."); +#endif + rx_state=N_RX_BLOCKED; + // have both delays (1ms + bytetime) + setEvent(SERIAL_RX_EVENT, bytetime*0.9f); } - else if(rxchar==-2) Disconnect(); - else setEvent(SERIAL_POLLING_EVENT, 1); - } else { - rx_retry++; - setEvent(SERIAL_POLLING_EVENT, 1); - } - } + break; + case N_RX_BLOCKED: + // one timeout tick + if(!CanReceiveByte()) { + rx_retry++; + if(rx_retry>=rx_retry_max) { + // it has timed out: + rx_retry=0; + removeEvent(SERIAL_RX_EVENT); + if(doReceive()) { + // read away everything + while(doReceive()); + rx_state=N_RX_WAIT; + setEvent(SERIAL_RX_EVENT, bytetime*0.9f); + } else { + // much trouble about nothing + rx_state=N_RX_IDLE; +#if SERIAL_DEBUG + log_ser(dbg_aux,"Nullmodem: unblock due to no more data",rx_retry); +#endif + } + } // else wait further + } else { + // good: we can receive again + removeEvent(SERIAL_RX_EVENT); + rx_retry=0; + if(doReceive()) { + rx_state=N_RX_FASTWAIT; + setEvent(SERIAL_RX_EVENT, bytetime*0.65f); + } else { + // much trouble about nothing + rx_state=N_RX_IDLE; + } + } + break; + + case N_RX_WAIT: + case N_RX_FASTWAIT: + break; + } break; } case SERIAL_RX_EVENT: { - // receive time is up, try to receive another byte. - receiveblock=false; - - if((!(LSR&LSR_RX_DATA_READY_MASK) || rx_retry>=rx_retry_max) - &&(!dtrrespect | (dtrrespect&& getDTR()) ) - ) { - rx_retry=0; - Bits rxchar = readChar(); - if(rxchar>=0) { - receiveblock=true; - setEvent(SERIAL_RX_EVENT, bytetime-0.01f); - receiveByte((Bit8u)rxchar); - } - else if(rxchar==-2) Disconnect(); - else setEvent(SERIAL_POLLING_EVENT, 1); - } else { - setEvent(SERIAL_POLLING_EVENT, 1); - rx_retry++; + switch(rx_state) { + case N_RX_IDLE: + LOG_MSG("internal error in nullmodem"); + break; + + case N_RX_BLOCKED: // try to receive + case N_RX_WAIT: + case N_RX_FASTWAIT: + if(CanReceiveByte()) { + // just works or unblocked + if(doReceive()) { + rx_retry=0; // not waiting anymore + if(rx_state==N_RX_WAIT) setEvent(SERIAL_RX_EVENT, bytetime*0.9f); + else { + // maybe unblocked + rx_state=N_RX_FASTWAIT; + setEvent(SERIAL_RX_EVENT, bytetime*0.65f); + } + } else { + // didn't receive anything + rx_retry=0; + rx_state=N_RX_IDLE; + } + } else { + // blocking now or still blocked +#if SERIAL_DEBUG + if(rx_state==N_RX_BLOCKED) + log_ser(dbg_aux,"Nullmodem: rx still blocked (retry=%d)",rx_retry); + else log_ser(dbg_aux,"Nullmodem: block on continued rx (retry=%d).",rx_retry); +#endif + setEvent(SERIAL_RX_EVENT, bytetime*0.65f); + rx_state=N_RX_BLOCKED; + } + + break; } break; } case SERIAL_TX_EVENT: { + // Maybe echo cirquit works a bit better this way + if(rx_state==N_RX_IDLE && CanReceiveByte() && clientsocket) { + if(doReceive()) { + // a byte was received + rx_state=N_RX_WAIT; + setEvent(SERIAL_RX_EVENT, bytetime*0.9f); + } + } ByteTransmitted(); break; } @@ -301,15 +377,18 @@ void CNullModem::handleUpperEvent(Bit16u type) { break; } case SERIAL_SERVER_POLLING_EVENT: { - // As long as nothing is connected to out server poll the + // As long as nothing is connected to our server poll the // connection. clientsocket=serversocket->Accept(); if(clientsocket) { Bit8u peeripbuf[16]; clientsocket->GetRemoteAddressString(peeripbuf); - LOG_MSG("Serial%d: A client (%s) has connected.",idnumber+1,peeripbuf); - // new socket found... + LOG_MSG("Serial%d: A client (%s) has connected.",COMNUMBER,peeripbuf); +#if SERIAL_DEBUG + log_ser(dbg_aux,"Nullmodem: A client (%s) has connected.", peeripbuf); +#endif// new socket found... clientsocket->SetSendBufferSize(256); + rx_state=N_RX_IDLE; setEvent(SERIAL_POLLING_EVENT, 1); // we don't accept further connections @@ -350,15 +429,23 @@ void CNullModem::updateMSR () { } +bool CNullModem::doReceive () { + Bits rxchar = readChar(); + if(rxchar>=0) { + receiveByteEx((Bit8u)rxchar,0); + return true; + } + else if(rxchar==-2) { + Disconnect(); + } + return false; +} + void CNullModem::transmitByte (Bit8u val, bool first) { + // transmit it later in THR_Event + if(first) setEvent(SERIAL_THR_EVENT, bytetime/8); + else setEvent(SERIAL_TX_EVENT, bytetime); - // transmit it later in THR_Event - if(first) { - setEvent(SERIAL_THR_EVENT, bytetime/8); - } else { - //if(clientsocket) clientsocket->Putchar(val); - setEvent(SERIAL_TX_EVENT, bytetime); - } // disable 0xff escaping when transparent mode is enabled if (!transparent && (val==0xff)) WriteChar(0xff); diff --git a/src/hardware/serialport/nullmodem.h b/src/hardware/serialport/nullmodem.h index 7869e3e6..395af647 100644 --- a/src/hardware/serialport/nullmodem.h +++ b/src/hardware/serialport/nullmodem.h @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: nullmodem.h,v 1.3 2009-05-27 09:15:41 qbix79 Exp $ */ +/* $Id: nullmodem.h,v 1.4 2009-09-25 23:40:47 h-a-l-9000 Exp $ */ // include guard #ifndef DOSBOX_NULLMODEM_WIN32_H @@ -57,6 +57,14 @@ public: void setDTR(bool val); void handleUpperEvent(Bit16u type); + Bitu rx_state; +#define N_RX_IDLE 0 +#define N_RX_WAIT 1 +#define N_RX_BLOCKED 2 +#define N_RX_FASTWAIT 3 +#define N_RX_DISC 4 + + bool doReceive(); void ClientConnect(); void Disconnect(); Bits readChar(); diff --git a/src/hardware/serialport/serialport.cpp b/src/hardware/serialport/serialport.cpp index fab9b220..84b4b330 100644 --- a/src/hardware/serialport/serialport.cpp +++ b/src/hardware/serialport/serialport.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: serialport.cpp,v 1.12 2009-05-27 09:15:41 qbix79 Exp $ */ +/* $Id: serialport.cpp,v 1.13 2009-09-25 23:40:47 h-a-l-9000 Exp $ */ #include #include @@ -30,15 +30,14 @@ #include "callback.h" // CALLBACK_Idle #include "serialport.h" -#include "directserial_win32.h" -#include "directserial_posix.h" -#include "directserial_os2.h" +#include "directserial.h" #include "serialdummy.h" #include "softmodem.h" #include "nullmodem.h" #include "cpu.h" +#define LOG_SER(x) log_ser bool device_COM::Read(Bit8u * data,Bit16u * size) { // DTR + RTS on @@ -98,97 +97,140 @@ device_COM::~device_COM() { CSerial* serialports[4] ={0,0,0,0}; static Bitu SERIAL_Read (Bitu port, Bitu iolen) { - for(Bitu i = 0; i < 4; i++) { - if(serial_baseaddr[i]==(port&0xfff8) && (serialports[i]!=0)) { - Bitu retval=0xff; - switch (port & 0x7) { - case RHR_OFFSET: - retval = serialports[i]->Read_RHR(); - break; - case IER_OFFSET: - retval = serialports[i]->Read_IER(); - break; - case ISR_OFFSET: - retval = serialports[i]->Read_ISR(); - break; - case LCR_OFFSET: - retval = serialports[i]->Read_LCR(); - break; - case MCR_OFFSET: - retval = serialports[i]->Read_MCR(); - break; - case LSR_OFFSET: - retval = serialports[i]->Read_LSR(); - break; - case MSR_OFFSET: - retval = serialports[i]->Read_MSR(); - break; - case SPR_OFFSET: - retval = serialports[i]->Read_SPR(); - break; - } + Bitu i; + Bitu retval; + Bitu index = port & 0x7; + switch(port&0xff8) { + case 0x3f8: i=0; break; + case 0x2f8: i=1; break; + case 0x3e8: i=2; break; + case 0x2e8: i=3; break; + default: return 0xff; + } + if(serialports[i]==0) return 0xff; + + switch (index) { + case RHR_OFFSET: + retval = serialports[i]->Read_RHR(); + break; + case IER_OFFSET: + retval = serialports[i]->Read_IER(); + break; + case ISR_OFFSET: + retval = serialports[i]->Read_ISR(); + break; + case LCR_OFFSET: + retval = serialports[i]->Read_LCR(); + break; + case MCR_OFFSET: + retval = serialports[i]->Read_MCR(); + break; + case LSR_OFFSET: + retval = serialports[i]->Read_LSR(); + break; + case MSR_OFFSET: + retval = serialports[i]->Read_MSR(); + break; + case SPR_OFFSET: + retval = serialports[i]->Read_SPR(); + break; + } #if SERIAL_DEBUG - const char* const dbgtext[]= - {"RHR","IER","ISR","LCR","MCR","LSR","MSR","SPR"}; - if(serialports[i]->dbg_register) - fprintf(serialports[i]->debugfp,"%12.3f read 0x%x from %s.\r\n", - PIC_FullIndex(),retval,dbgtext[port&0x7]); -#endif - - return retval; - } + const char* const dbgtext[]= + {"RHR","IER","ISR","LCR","MCR","LSR","MSR","SPR","DLL","DLM"}; + if(serialports[i]->dbg_register) { + if((index<2) && ((serialports[i]->LCR)&LCR_DIVISOR_Enable_MASK)) + index += 8; + serialports[i]->log_ser(serialports[i]->dbg_register, + "read 0x%2x from %s.",retval,dbgtext[index]); } - return 0xff; +#endif + return retval; } static void SERIAL_Write (Bitu port, Bitu val, Bitu) { + Bitu i; + Bitu index = port & 0x7; + switch(port&0xff8) { + case 0x3f8: i=0; break; + case 0x2f8: i=1; break; + case 0x3e8: i=2; break; + case 0x2e8: i=3; break; + default: return; + } + if(serialports[i]==0) return; - for(Bitu i = 0; i < 4; i++) { - if(serial_baseaddr[i]==(port&0xfff8) && serialports[i]) { - #if SERIAL_DEBUG - const char* const dbgtext[]={"THR","IER","FCR","LCR","MCR","!LSR","MSR","SPR"}; - if(serialports[i]->dbg_register) - fprintf(serialports[i]->debugfp,"%12.3f write 0x%x to %s.\r\n", - PIC_FullIndex(),val,dbgtext[port&0x7]); -#endif - - switch (port & 0x7) { - case THR_OFFSET: - serialports[i]->Write_THR (val); - return; - case IER_OFFSET: - serialports[i]->Write_IER (val); - return; - case FCR_OFFSET: - serialports[i]->Write_FCR (val); - return; - case LCR_OFFSET: - serialports[i]->Write_LCR (val); - return; - case MCR_OFFSET: - serialports[i]->Write_MCR (val); - return; - case MSR_OFFSET: - serialports[i]->Write_MSR (val); - return; - case SPR_OFFSET: - serialports[i]->Write_SPR (val); - return; - default: - serialports[i]->Write_reserved (val, port & 0x7); - } + const char* const dbgtext[]={"THR","IER","FCR", + "LCR","MCR","!LSR","MSR","SPR","DLL","DLM"}; + if(serialports[i]->dbg_register) { + Bitu debugindex=index; + if((index<2) && ((serialports[i]->LCR)&LCR_DIVISOR_Enable_MASK)) + debugindex += 8; + serialports[i]->log_ser(serialports[i]->dbg_register, + "write 0x%2x to %s.",val,dbgtext[debugindex]); } +#endif + switch (index) { + case THR_OFFSET: + serialports[i]->Write_THR (val); + return; + case IER_OFFSET: + serialports[i]->Write_IER (val); + return; + case FCR_OFFSET: + serialports[i]->Write_FCR (val); + return; + case LCR_OFFSET: + serialports[i]->Write_LCR (val); + return; + case MCR_OFFSET: + serialports[i]->Write_MCR (val); + return; + case MSR_OFFSET: + serialports[i]->Write_MSR (val); + return; + case SPR_OFFSET: + serialports[i]->Write_SPR (val); + return; + default: + serialports[i]->Write_reserved (val, port & 0x7); } } +#if SERIAL_DEBUG +void CSerial::log_ser(bool active, char const* format,...) { + if(active) { + // copied from DEBUG_SHOWMSG + char buf[512]; + buf[0]=0; + sprintf(buf,"%12.3f [% 7u] ",PIC_FullIndex(), SDL_GetTicks()); + va_list msg; + va_start(msg,format); + vsprintf(buf+strlen(buf),format,msg); + va_end(msg); + // Add newline if not present + Bitu len=strlen(buf); + if(buf[len-1]!='\n') strcat(buf,"\r\n"); + fputs(buf,debugfp); + } +} +#endif void CSerial::changeLineProperties() { // update the event wait time + float bitlen; - float bitlen = (1000.0f/115200.0f)*(float)baud_divider; + if(baud_divider==0) bitlen=(1000.0f/115200.0f); + else bitlen = (1000.0f/115200.0f)*(float)baud_divider; bytetime=bitlen*(float)(1+5+1); // startbit + minimum length + stopbit bytetime+= bitlen*(float)(LCR&0x3); // databits if(LCR&0x4) bytetime+=bitlen; // stopbit + +#if SERIAL_DEBUG + const char* const dbgtext[]={"none","odd","none","even","none","mark","none","space"}; + log_ser(dbg_serialtraffic,"New COM parameters: baudrate %5.0f, parity %s, wordlen %d, stopbits %d", + 1.0/bitlen*1000.0f,dbgtext[(LCR&0x38)>>3],(LCR&0x3)+5,((LCR&0x4)>>2)+1); +#endif updatePortConfig (baud_divider, LCR); } @@ -212,35 +254,38 @@ void CSerial::handleEvent(Bit16u type) { case SERIAL_TX_LOOPBACK_EVENT: { #if SERIAL_DEBUG - if(dbg_serialtraffic) - fprintf(debugfp,loopback_data<0x10? "%12.3f tx 0x%02x (%u) (loopback)\r\n": - "%12.3f tx 0x%02x (%c) (loopback)\r\n", - PIC_FullIndex(),loopback_data, - loopback_data); + log_ser(dbg_serialtraffic,loopback_data<0x10? + "tx 0x%02x (%u) (loopback)":"tx 0x%02x (%c) (loopback)", + loopback_data, loopback_data); #endif - receiveByte (loopback_data); ByteTransmitted (); break; } case SERIAL_THR_LOOPBACK_EVENT: { + loopback_data=txfifo->probeByte(); ByteTransmitting(); - loopback_data=THR; setEvent(SERIAL_TX_LOOPBACK_EVENT,bytetime); break; } case SERIAL_ERRMSG_EVENT: { - LOG_MSG("Serial%d: Errors occured: "\ - "Framing %d, Parity %d, Overrun %d (IF0:%d), Break %d", COMNUMBER, - framingErrors, parityErrors, overrunErrors, overrunIF0, breakErrors); + LOG_MSG("Serial%d: Errors: "\ + "Framing %d, Parity %d, Overrun RX:%d (IF0:%d), TX:%d, Break %d", + COMNUMBER, framingErrors, parityErrors, overrunErrors, + overrunIF0,txOverrunErrors, breakErrors); errormsg_pending=false; framingErrors=0; parityErrors=0; overrunErrors=0; + txOverrunErrors=0; overrunIF0=0; breakErrors=0; break; } + case SERIAL_RX_TIMEOUT_EVENT: { + rise(TIMEOUT_PRIORITY); + break; + } default: handleUpperEvent(type); } } @@ -250,20 +295,14 @@ void CSerial::handleEvent(Bit16u type) { /*****************************************************************************/ void CSerial::rise (Bit8u priority) { #if SERIAL_DEBUG - if(dbg_interrupt) - { - if(priority&TX_PRIORITY && !(waiting_interrupts&TX_PRIORITY)) - fprintf(debugfp,"%12.3f tx interrupt on.\r\n",PIC_FullIndex()); - - if(priority&RX_PRIORITY && !(waiting_interrupts&RX_PRIORITY)) - fprintf(debugfp,"%12.3f rx interrupt on.\r\n",PIC_FullIndex()); - - if(priority&MSR_PRIORITY && !(waiting_interrupts&MSR_PRIORITY)) - fprintf(debugfp,"%12.3f msr interrupt on.\r\n",PIC_FullIndex()); - - if(priority&ERROR_PRIORITY && !(waiting_interrupts&ERROR_PRIORITY)) - fprintf(debugfp,"%12.3f error interrupt on.\r\n",PIC_FullIndex()); - } + if(priority&TX_PRIORITY && !(waiting_interrupts&TX_PRIORITY)) + log_ser(dbg_interrupt,"tx interrupt on."); + if(priority&RX_PRIORITY && !(waiting_interrupts&RX_PRIORITY)) + log_ser(dbg_interrupt,"rx interrupt on."); + if(priority&MSR_PRIORITY && !(waiting_interrupts&MSR_PRIORITY)) + log_ser(dbg_interrupt,"msr interrupt on."); + if(priority&TIMEOUT_PRIORITY && !(waiting_interrupts&TIMEOUT_PRIORITY)) + log_ser(dbg_interrupt,"fifo rx timeout interrupt on."); #endif waiting_interrupts |= priority; @@ -274,23 +313,15 @@ void CSerial::rise (Bit8u priority) { void CSerial::clear (Bit8u priority) { #if SERIAL_DEBUG - if(dbg_interrupt) - { - if(priority&TX_PRIORITY && (waiting_interrupts&TX_PRIORITY)) - fprintf(debugfp,"%12.3f tx interrupt off.\r\n",PIC_FullIndex()); - - if(priority&RX_PRIORITY && (waiting_interrupts&RX_PRIORITY)) - fprintf(debugfp,"%12.3f rx interrupt off.\r\n",PIC_FullIndex()); - - if(priority&MSR_PRIORITY && (waiting_interrupts&MSR_PRIORITY)) - fprintf(debugfp,"%12.3f msr interrupt off.\r\n",PIC_FullIndex()); - - if(priority&ERROR_PRIORITY && (waiting_interrupts&ERROR_PRIORITY)) - fprintf(debugfp,"%12.3f error interrupt off.\r\n",PIC_FullIndex()); - } + if(priority&TX_PRIORITY && (waiting_interrupts&TX_PRIORITY)) + log_ser(dbg_interrupt,"tx interrupt off."); + if(priority&RX_PRIORITY && (waiting_interrupts&RX_PRIORITY)) + log_ser(dbg_interrupt,"rx interrupt off."); + if(priority&MSR_PRIORITY && (waiting_interrupts&MSR_PRIORITY)) + log_ser(dbg_interrupt,"msr interrupt off."); + if(priority&ERROR_PRIORITY && (waiting_interrupts&ERROR_PRIORITY)) + log_ser(dbg_interrupt,"error interrupt off."); #endif - - waiting_interrupts &= (~priority); ComputeInterrupts(); } @@ -299,30 +330,30 @@ void CSerial::ComputeInterrupts () { Bitu val = IER & waiting_interrupts; - if (val & ERROR_PRIORITY) ISR = ISR_ERROR_VAL; - else if (val & RX_PRIORITY) ISR = ISR_RX_VAL; - else if (val & TX_PRIORITY) ISR = ISR_TX_VAL; - else if (val & MSR_PRIORITY) ISR = ISR_MSR_VAL; + if (val & ERROR_PRIORITY) ISR = ISR_ERROR_VAL; + else if (val & TIMEOUT_PRIORITY) ISR = ISR_FIFOTIMEOUT_VAL; + else if (val & RX_PRIORITY) ISR = ISR_RX_VAL; + else if (val & TX_PRIORITY) ISR = ISR_TX_VAL; + else if (val & MSR_PRIORITY) ISR = ISR_MSR_VAL; else ISR = ISR_CLEAR_VAL; - if(val && !irq_active) { + if(val && !irq_active) + { irq_active=true; - PIC_ActivateIRQ(irq); - + if(op2) { + PIC_ActivateIRQ(irq); #if SERIAL_DEBUG - if(dbg_interrupt) - fprintf(debugfp,"%12.3f IRQ%d on.\r\n",PIC_FullIndex(),irq); + log_ser(dbg_interrupt,"IRQ%d on.",irq); #endif - } - - if(!val && irq_active) { + } + } else if((!val) && irq_active) { irq_active=false; - PIC_DeActivateIRQ(irq); - + if(op2) { + PIC_DeActivateIRQ(irq); #if SERIAL_DEBUG - if(dbg_interrupt) - fprintf(debugfp,"%12.3f IRQ%d off.\r\n",PIC_FullIndex(),irq); + log_ser(dbg_interrupt,"IRQ%d off.",irq); #endif + } } } @@ -330,108 +361,99 @@ void CSerial::ComputeInterrupts () { /* Can a byte be received? **/ /*****************************************************************************/ bool CSerial::CanReceiveByte() { - return (LSR & LSR_RX_DATA_READY_MASK) == 0; + return !rxfifo->isFull(); } /*****************************************************************************/ /* A byte was received **/ /*****************************************************************************/ -void CSerial::receiveByte (Bit8u data) { - +void CSerial::receiveByteEx (Bit8u data, Bit8u error) { + printf("%c",data); #if SERIAL_DEBUG - if(dbg_serialtraffic) - fprintf(debugfp,loopback_data<0x10? "%12.3f rx 0x%02x (%u)\r\n": - "%12.3f rx 0x%02x (%c)\r\n", - PIC_FullIndex(), data, data); + log_ser(dbg_serialtraffic,data<0x10 ? "\t\t\t\trx 0x%02x (%u)": + "\t\t\t\trx 0x%02x (%c)", data, data); #endif + if (!(rxfifo->addb(data))) { + // Overrun error ;o + error |= LSR_OVERRUN_ERROR_MASK; + } + removeEvent(SERIAL_RX_TIMEOUT_EVENT); + if(rxfifo->getUsage()==rx_interrupt_threshold) rise (RX_PRIORITY); + else setEvent(SERIAL_RX_TIMEOUT_EVENT,bytetime*4.0f); - if (LSR & LSR_RX_DATA_READY_MASK) { // Overrun error ;o + if(error) { + // A lot of UART chips generate a framing error too when receiving break + if(error&LSR_RX_BREAK_MASK) error |= LSR_FRAMING_ERROR_MASK; +#if SERIAL_DEBUG + log_ser(dbg_serialtraffic,"with error: framing=%d,overrun=%d,break=%d,parity=%d", + (error&LSR_FRAMING_ERROR_MASK)>0,(error&LSR_OVERRUN_ERROR_MASK)>0, + (error&LSR_RX_BREAK_MASK)>0,(error&LSR_PARITY_ERROR_MASK)>0); +#endif + if(FCR&FCR_ACTIVATE) { + // error and FIFO active + if(!errorfifo->isFull()) { + errors_in_fifo++; + errorfifo->addb(error); + } + else { + Bit8u toperror=errorfifo->getTop(); + if(!toperror) errors_in_fifo++; + errorfifo->addb(error|toperror); + } + if(errorfifo->probeByte()) { + // the next byte in the error fifo has an error + rise (ERROR_PRIORITY); + LSR |= error; + } + } else { + // error and FIFO inactive + rise (ERROR_PRIORITY); + LSR |= error; + }; + if(error&LSR_PARITY_ERROR_MASK) { + parityErrors++; + }; + if(error&LSR_OVERRUN_ERROR_MASK) { + overrunErrors++; + if(!GETFLAG(IF)) overrunIF0++; +#if SERIAL_DEBUG + log_ser(dbg_serialtraffic,"rx overrun (IF=%d)", GETFLAG(IF)>0); +#endif + }; + if(error&LSR_FRAMING_ERROR_MASK) { + framingErrors++; + } + if(error&LSR_RX_BREAK_MASK) { + breakErrors++; + } + // trigger status window error notification if(!errormsg_pending) { errormsg_pending=true; setEvent(SERIAL_ERRMSG_EVENT,1000); } - overrunErrors++; - Bitu iflag= GETFLAG(IF); - if(!iflag)overrunIF0++; - -#if SERIAL_DEBUG - if(dbg_serialtraffic) - fprintf(debugfp, "%12.3f rx overrun (IF=%d)\r\n", - PIC_FullIndex(), iflag); -#endif - - LSR |= LSR_OVERRUN_ERROR_MASK; - rise (ERROR_PRIORITY); } else { - RHR = data; - LSR |= LSR_RX_DATA_READY_MASK; - rise (RX_PRIORITY); + // no error + if(FCR&FCR_ACTIVATE) { + errorfifo->addb(error); + } } } -/*****************************************************************************/ -/* A line error was received **/ -/*****************************************************************************/ -void CSerial::receiveError (Bit8u errorword) { - - if(!errormsg_pending) { - errormsg_pending=true; - setEvent(SERIAL_ERRMSG_EVENT,1000); - } - if(errorword&LSR_PARITY_ERROR_MASK) { - parityErrors++; - -#if SERIAL_DEBUG - if(dbg_serialtraffic) - fprintf(debugfp, "%12.3f parity error\r\n", - PIC_FullIndex()); -#endif - - } - if(errorword&LSR_FRAMING_ERROR_MASK) { - framingErrors++; - -#if SERIAL_DEBUG - if(dbg_serialtraffic) - fprintf(debugfp, "%12.3f framing error\r\n", - PIC_FullIndex()); -#endif - - } - if(errorword&LSR_RX_BREAK_MASK) { - breakErrors++; - -#if SERIAL_DEBUG - if(dbg_serialtraffic) - fprintf(debugfp, "%12.3f break received\r\n", - PIC_FullIndex()); -#endif - - } - LSR |= errorword; - - rise (ERROR_PRIORITY); +void CSerial::receiveByte (Bit8u data) { + receiveByteEx(data,0); } /*****************************************************************************/ /* ByteTransmitting: Byte has made it from THR to TX. **/ /*****************************************************************************/ void CSerial::ByteTransmitting() { - switch(LSR&(LSR_TX_HOLDING_EMPTY_MASK|LSR_TX_EMPTY_MASK)) - { - case LSR_TX_HOLDING_EMPTY_MASK|LSR_TX_EMPTY_MASK: - // bad case there must have been one - case LSR_TX_HOLDING_EMPTY_MASK: - case LSR_TX_EMPTY_MASK: // holding full but workreg empty impossible - LOG_MSG("Internal error in serial port(1)(0x%x).",LSR); - break; - case 0: // THR is empty now. - LSR |= LSR_TX_HOLDING_EMPTY_MASK; - - // trigger interrupt - rise (TX_PRIORITY); - break; - } + if(sync_guardtime) { + //LOG_MSG("byte transmitting after guard"); + //if(txfifo->isEmpty()) LOG_MSG("Serial port: FIFO empty when it should not"); + sync_guardtime=false; + txfifo->getb(); + } //else LOG_MSG("byte transmitting"); + if(txfifo->isEmpty())rise (TX_PRIORITY); } @@ -439,39 +461,23 @@ void CSerial::ByteTransmitting() { /* ByteTransmitted: When a byte was sent, notify here. **/ /*****************************************************************************/ void CSerial::ByteTransmitted () { - switch(LSR&(LSR_TX_HOLDING_EMPTY_MASK|LSR_TX_EMPTY_MASK)) - { - case LSR_TX_HOLDING_EMPTY_MASK|LSR_TX_EMPTY_MASK: - // bad case there must have been one - case LSR_TX_EMPTY_MASK: // holding full but workreg empty impossible - LOG_MSG("Internal error in serial port(2)."); - break; - - case LSR_TX_HOLDING_EMPTY_MASK: // now both are empty - LSR |= LSR_TX_EMPTY_MASK; - break; + if(!txfifo->isEmpty()) { + // there is more data + Bit8u data = txfifo->getb(); +#if SERIAL_DEBUG + log_ser(dbg_serialtraffic,data<0x10? + "\t\t\t\t\ttx 0x%02x (%u) (from buffer)": + "\t\t\t\t\ttx 0x%02x (%c) (from buffer)",data,data); +#endif + if (loopback) setEvent(SERIAL_TX_LOOPBACK_EVENT, bytetime); + else transmitByte(data,false); + if(txfifo->isEmpty())rise (TX_PRIORITY); - case 0: // now one is empty, send the other one - LSR |= LSR_TX_HOLDING_EMPTY_MASK; - if (loopback) { - loopback_data=THR; - setEvent(SERIAL_TX_LOOPBACK_EVENT, bytetime); - } - else { - - #if SERIAL_DEBUG - if(dbg_serialtraffic) - fprintf(debugfp,THR<0x10? "%12.3f tx 0x%02x (%u) (from THR)\r\n": - "%12.3f tx 0x%02x (%c) (from THR)\r\n", - PIC_FullIndex(),THR, - THR); - #endif - - transmitByte(THR,false); - } - // It's ok here. - rise (TX_PRIORITY); - break; + } else { +#if SERIAL_DEBUG + log_ser(dbg_serialtraffic,"tx buffer empty."); +#endif + LSR |= LSR_TX_EMPTY_MASK; } } @@ -488,51 +494,43 @@ void CSerial::Write_THR (Bit8u data) { changeLineProperties(); } else { // write to THR - clear (TX_PRIORITY); + clear (TX_PRIORITY); - switch(LSR&(LSR_TX_HOLDING_EMPTY_MASK|LSR_TX_EMPTY_MASK)) - { - case 0: // both full - overflow -#if SERIAL_DEBUG - if(dbg_serialtraffic) fprintf(debugfp, "%12.3f tx overflow\r\n", - PIC_FullIndex()); -#endif - // overwrite THR - THR = data; - break; - - case LSR_TX_EMPTY_MASK: // holding full but workreg empty impossible - LOG_MSG("Internal error in serial port(3)."); - break; - - case LSR_TX_HOLDING_EMPTY_MASK: // now both are full - LSR &= (~LSR_TX_HOLDING_EMPTY_MASK); - THR = data; - break; - - case LSR_TX_HOLDING_EMPTY_MASK|LSR_TX_EMPTY_MASK: - // both are full until the first delay has passed - THR=data; - LSR &= (~LSR_TX_EMPTY_MASK); - LSR &= (~LSR_TX_HOLDING_EMPTY_MASK); - if(loopback) setEvent(SERIAL_THR_LOOPBACK_EVENT, bytetime/10); - else { + if((LSR & LSR_TX_EMPTY_MASK)) + { // we were idle before + //LOG_MSG("starting new transmit cycle"); + //if(sync_guardtime) LOG_MSG("Serial port internal error 1"); + //if(!(LSR & LSR_TX_EMPTY_MASK)) LOG_MSG("Serial port internal error 2"); + //if(txfifo->getUsage()) LOG_MSG("Serial port internal error 3"); + // need "warming up" time + sync_guardtime=true; + // block the fifo so it returns THR full (or not in case of FIFO on) + txfifo->addb(data); + // transmit shift register is busy + LSR &= (~LSR_TX_EMPTY_MASK); + if(loopback) setEvent(SERIAL_THR_LOOPBACK_EVENT, bytetime/10); + else { #if SERIAL_DEBUG - if(dbg_serialtraffic) - fprintf(debugfp,data<0x10? "%12.3f tx 0x%02x (%u)\r\n": - "%12.3f tx 0x%02x (%c)\r\n", - PIC_FullIndex(),data, - data); -#endif - - transmitByte (data,true); + log_ser(dbg_serialtraffic,data<0x10? + "\t\t\t\t\ttx 0x%02x (%u) [FIFO=%2d]": + "\t\t\t\t\ttx 0x%02x (%c) [FIFO=%2d]",data,data,txfifo->getUsage()); +#endif + transmitByte (data,true); + } + } else { + // shift register is transmitting + if(!txfifo->addb(data)) { + // TX overflow +#if SERIAL_DEBUG + log_ser(dbg_serialtraffic,"tx overflow"); +#endif + txOverrunErrors++; + if(!errormsg_pending) { + errormsg_pending=true; + setEvent(SERIAL_ERRMSG_EVENT,1000); } - - // triggered - // when holding gets empty - // rise (TX_PRIORITY); - break; + } } } } @@ -545,9 +543,26 @@ Bitu CSerial::Read_RHR () { // 0-7 received data if ((LCR & LCR_DIVISOR_Enable_MASK)) return baud_divider&0xff; else { - clear (RX_PRIORITY); - LSR &= (~LSR_RX_DATA_READY_MASK); - return RHR; + Bit8u data=rxfifo->getb(); + if(FCR&FCR_ACTIVATE) { + Bit8u error=errorfifo->getb(); + if(error) errors_in_fifo--; + // new error + if(!rxfifo->isEmpty()) { + error=errorfifo->probeByte(); + if(error) { + LSR |= error; + rise(ERROR_PRIORITY); + } + } + } + // Reading RHR resets the FIFO timeout + clear (TIMEOUT_PRIORITY); + // RX int. is cleared if the buffer holds less data than the threshold + if(rxfifo->getUsage()isEmpty()) setEvent(SERIAL_RX_TIMEOUT_EVENT,bytetime*4.0f); + return data; } } @@ -564,7 +579,7 @@ Bitu CSerial::Read_IER () { // 4-7 0 if (LCR & LCR_DIVISOR_Enable_MASK) return baud_divider>>8; - else return IER; + else return IER&0x0f; } void CSerial::Write_IER (Bit8u data) { @@ -573,11 +588,12 @@ void CSerial::Write_IER (Bit8u data) { baud_divider |= ((Bit16u)data)<<8; changeLineProperties(); } else { - - IER = data&0xF; - if ((LSR & LSR_TX_HOLDING_EMPTY_MASK) && (IER&TX_PRIORITY)) + // Retrigger TX interrupt + if (txfifo->isEmpty()&& (data&TX_PRIORITY)) waiting_interrupts |= TX_PRIORITY; + IER = data&0xF; + if((FCR&FCR_ACTIVATE)&&data&RX_PRIORITY) IER |= TIMEOUT_PRIORITY; ComputeInterrupts(); } } @@ -593,6 +609,7 @@ Bitu CSerial::Read_ISR () { // 1-3 identification // 011 LSR // 010 RXRDY + // 110 RX_TIMEOUT // 001 TXRDY // 000 MSR // 4-7 0 @@ -601,14 +618,44 @@ Bitu CSerial::Read_ISR () { Bit8u retval = ISR; // clear changes ISR!! mean.. - if(ISR==ISR_TX_VAL) clear (TX_PRIORITY); + if(ISR==ISR_TX_VAL) clear(TX_PRIORITY); + if(FCR&FCR_ACTIVATE) retval |= FIFO_STATUS_ACTIVE; + return retval; } +#define BIT_CHANGE_H(oldv,newv,bitmask) (!(oldv&bitmask) && (newv&bitmask)) +#define BIT_CHANGE_L(oldv,newv,bitmask) ((oldv&bitmask) && !(newv&bitmask)) + void CSerial::Write_FCR (Bit8u data) { - if((!fifo_warn) && (data&0x1)) { - fifo_warn=true; - LOG_MSG("Serial%d: Warning: Tried to activate FIFO.",COMNUMBER); + if(BIT_CHANGE_H(FCR,data,FCR_ACTIVATE)) { + // FIFO was switched on + errors_in_fifo=0; // should already be 0 + errorfifo->setSize(fifosize); + rxfifo->setSize(fifosize); + txfifo->setSize(fifosize); + } else if(BIT_CHANGE_L(FCR,data,FCR_ACTIVATE)) { + // FIFO was switched off + errors_in_fifo=0; + errorfifo->setSize(1); + rxfifo->setSize(1); + txfifo->setSize(1); + rx_interrupt_threshold=1; + } + FCR=data&0xCF; + if(FCR&FCR_CLEAR_RX) { + errors_in_fifo=0; + errorfifo->clear(); + rxfifo->clear(); + } + if(FCR&FCR_CLEAR_TX) txfifo->clear(); + if(FCR&FCR_ACTIVATE) { + switch(FCR>>6) { + case 0: rx_interrupt_threshold=1; break; + case 1: rx_interrupt_threshold=4; break; + case 2: rx_interrupt_threshold=8; break; + case 3: rx_interrupt_threshold=14; break; + } } } @@ -643,10 +690,8 @@ void CSerial::Write_LCR (Bit8u data) { // TODO: set loopback break event to reveiveError after } #if SERIAL_DEBUG - if(dbg_serialtraffic) - fprintf(debugfp,((LCR & LCR_BREAK_MASK)!=0)? - "%12.3f break on.\r\n": - "%12.3f break off.\r\n", PIC_FullIndex()); + log_ser(dbg_serialtraffic,((LCR & LCR_BREAK_MASK)!=0) ? + "break on.":"break off."); #endif } } @@ -675,7 +720,7 @@ Bitu CSerial::Read_MCR () { void CSerial::Write_MCR (Bit8u data) { // WARNING: At the time setRTSDTR is called rts and dsr members are still wrong. - + if(data&FIFO_FLOWCONTROL) LOG_MSG("Warning: tried to activate hardware handshake."); bool temp_dtr = data & MCR_DTR_MASK? true:false; bool temp_rts = data & MCR_RTS_MASK? true:false; bool temp_op1 = data & MCR_OP1_MASK? true:false; @@ -718,34 +763,34 @@ void CSerial::Write_MCR (Bit8u data) { // both difference #if SERIAL_DEBUG - if(dbg_modemcontrol) - { - fprintf(debugfp,temp_rts?"%12.3f RTS on.\r\n": - "%12.3f RTS off.\r\n", PIC_FullIndex()); - fprintf(debugfp,temp_dtr?"%12.3f DTR on.\r\n": - "%12.3f DTR off.\r\n", PIC_FullIndex()); - } + log_ser(dbg_modemcontrol,"RTS %x.",temp_rts); + log_ser(dbg_modemcontrol,"DTR %x.",temp_dtr); #endif setRTSDTR(temp_rts, temp_dtr); } else { // only RTS #if SERIAL_DEBUG - if(dbg_modemcontrol) - fprintf(debugfp,temp_rts?"%12.3f RTS on.\r\n":"%12.3f RTS off.\r\n", PIC_FullIndex()); + log_ser(dbg_modemcontrol,"RTS %x.",temp_rts); #endif - setRTS(temp_rts); } } else if(temp_dtr!=dtr) { // only DTR #if SERIAL_DEBUG - if(dbg_modemcontrol) - fprintf(debugfp,temp_dtr?"%12.3f DTR on.\r\n":"%12.3f DTR off.\r\n", PIC_FullIndex()); + log_ser(dbg_modemcontrol,"%DTR %x.",temp_dtr); #endif setDTR(temp_dtr); } } + // interrupt logic: if OP2 is 0, the IRQ line is tristated (pulled high) + if((!op2) && temp_op2) { + // irq has been enabled (tristate high -> irq level) + if(!irq_active) PIC_DeActivateIRQ(irq); + } else if(op2 && (!temp_op2)) { + if(!irq_active) PIC_ActivateIRQ(irq); + } + dtr=temp_dtr; rts=temp_rts; op1=temp_op1; @@ -761,7 +806,10 @@ void CSerial::Write_MCR (Bit8u data) { // - event from real serial port // - loopback Bitu CSerial::Read_LSR () { - Bitu retval = LSR; + Bitu retval = LSR & (LSR_ERROR_MASK|LSR_TX_EMPTY_MASK); + if(txfifo->isEmpty()) retval |= LSR_TX_HOLDING_EMPTY_MASK; + if(!(rxfifo->isEmpty()))retval |= LSR_RX_DATA_READY_MASK; + if(errors_in_fifo) retval |= FIFO_ERROR; LSR &= (~LSR_ERROR_MASK); // clear error bits on read clear (ERROR_PRIORITY); return retval; @@ -872,8 +920,7 @@ void CSerial::setRI (bool value) { if (value != ri) { #if SERIAL_DEBUG - if(dbg_modemcontrol) - fprintf(debugfp,value?"%12.3f RI on.\r\n":"%12.3f RI off.\r\n", PIC_FullIndex()); + log_ser(dbg_modemcontrol,"%RI %x.",value); #endif // don't change delta when in loopback mode ri=value; @@ -887,8 +934,7 @@ void CSerial::setRI (bool value) { void CSerial::setDSR (bool value) { if (value != dsr) { #if SERIAL_DEBUG - if(dbg_modemcontrol) - fprintf(debugfp,value?"%12.3f DSR on.\r\n":"%12.3f DSR off.\r\n", PIC_FullIndex()); + log_ser(dbg_modemcontrol,"DSR %x.",value); #endif // don't change delta when in loopback mode dsr=value; @@ -902,8 +948,7 @@ void CSerial::setDSR (bool value) { void CSerial::setCD (bool value) { if (value != cd) { #if SERIAL_DEBUG - if(dbg_modemcontrol) - fprintf(debugfp,value?"%12.3f CD on.\r\n":"%12.3f CD off.\r\n", PIC_FullIndex()); + log_ser(dbg_modemcontrol,"CD %x.",value); #endif // don't change delta when in loopback mode cd=value; @@ -917,8 +962,7 @@ void CSerial::setCD (bool value) { void CSerial::setCTS (bool value) { if (value != cts) { #if SERIAL_DEBUG - if(dbg_modemcontrol) - fprintf(debugfp,value?"%12.3f CTS on.\r\n":"%12.3f CTS off.\r\n", PIC_FullIndex()); + log_ser(dbg_modemcontrol,"CTS %x.",value); #endif // don't change delta when in loopback mode cts=value; @@ -945,8 +989,6 @@ void CSerial::Init_Registers () { Bit8u lcrresult = 0; Bit16u baudresult = 0; - RHR = 0; - THR = 0; IER = 0; ISR = 0x1; LCR = 0; @@ -957,6 +999,10 @@ void CSerial::Init_Registers () { op1=true; op2=true; + sync_guardtime=false; + FCR=0xff; + Write_FCR(0x00); + LSR = 0x60; d_cts = true; @@ -1023,6 +1069,12 @@ void CSerial::Init_Registers () { } CSerial::CSerial(Bitu id, CommandLine* cmd) { + idnumber=id; + Bit16u base = serial_baseaddr[id]; + + irq = serial_defaultirq[id]; + getBituSubstring("irq:",&irq, cmd); + if (irq < 2 || irq > 15) irq = serial_defaultirq[id]; #if SERIAL_DEBUG dbg_serialtraffic = cmd->FindExist("dbgtr", false); @@ -1030,44 +1082,55 @@ CSerial::CSerial(Bitu id, CommandLine* cmd) { dbg_register = cmd->FindExist("dbgreg", false); dbg_interrupt = cmd->FindExist("dbgirq", false); dbg_aux = cmd->FindExist("dbgaux", false); + + if(cmd->FindExist("dbgall", false)) { + dbg_serialtraffic= + dbg_modemcontrol= + dbg_register= + dbg_interrupt= + dbg_aux= true; + } if(dbg_serialtraffic|dbg_modemcontrol|dbg_register|dbg_interrupt|dbg_aux) debugfp=OpenCaptureFile("serlog",".serlog.txt"); else debugfp=0; + if(debugfp == 0) { + dbg_serialtraffic= + dbg_modemcontrol= + dbg_register= + dbg_interrupt= + dbg_aux= false; + } else { + std::string cleft; + cmd->GetStringRemain(cleft); + + log_ser(true,"Serial%d: BASE %3x, IRQ %d, initstring \"%s\"\r\n\r\n", + COMNUMBER,base,irq,cleft.c_str()); + } #endif + fifosize=16; + errorfifo = new MyFifo(fifosize); + rxfifo = new MyFifo(fifosize); + txfifo = new MyFifo(fifosize); - - idnumber=id; mydosdevice=new device_COM(this); DOS_AddDevice(mydosdevice); - Bit16u base = serial_baseaddr[id]; - fifo_warn=false; errormsg_pending=false; framingErrors=0; parityErrors=0; overrunErrors=0; + txOverrunErrors=0; overrunIF0=0; breakErrors=0; - // find the IRQ - irq = serial_defaultirq[id]; - getBituSubstring("irq:",&irq, cmd); - if (irq < 2 || irq > 15) irq = serial_defaultirq[id]; - - for (Bitu i = 0; i <= 7; i++) { WriteHandler[i].Install (i + base, SERIAL_Write, IO_MB); ReadHandler[i].Install (i + base, SERIAL_Read, IO_MB); } - -#if SERIAL_DEBUG - if(debugfp) fprintf(debugfp,"COM%d: BASE %3x, IRQ %d\r\n\r\n", - COMNUMBER,base,irq); -#endif } bool CSerial::getBituSubstring(const char* name,Bitu* data, CommandLine* cmd) { @@ -1082,19 +1145,16 @@ CSerial::~CSerial(void) { DOS_DelDevice(mydosdevice); for(Bitu i = 0; i <= SERIAL_BASE_EVENT_COUNT; i++) removeEvent(i); -} +}; bool CSerial::Getchar(Bit8u* data, Bit8u* lsr, bool wait_dsr, Bitu timeout) { - double starttime=PIC_FullIndex(); - // wait for it to become empty // wait for DSR on if(wait_dsr) { while((!(Read_MSR()&0x20))&&(starttime>PIC_FullIndex()-timeout)) CALLBACK_Idle(); if(!(starttime>PIC_FullIndex()-timeout)) { - #if SERIAL_DEBUG -if(dbg_aux) - fprintf(debugfp,"%12.3f Getchar status timeout: MSR 0x%x\r\n", PIC_FullIndex(),Read_MSR()); +#if SERIAL_DEBUG + log_ser(dbg_aux,"Getchar status timeout: MSR 0x%x",Read_MSR()); #endif return false; } @@ -1104,21 +1164,16 @@ if(dbg_aux) CALLBACK_Idle(); if(!(starttime>PIC_FullIndex()-timeout)) { - #if SERIAL_DEBUG -if(dbg_aux) - fprintf(debugfp,"%12.3f Getchar data timeout: MSR 0x%x\r\n", PIC_FullIndex(),Read_MSR()); +#if SERIAL_DEBUG + log_ser(dbg_aux,"Getchar data timeout: MSR 0x%x",Read_MSR()); #endif return false; } - - *data=Read_RHR(); #if SERIAL_DEBUG - if(dbg_aux) - fprintf(debugfp,"%12.3f API read success: 0x%x\r\n", PIC_FullIndex(),*data); + log_ser(dbg_aux,"Getchar read 0x%x",*data); #endif - return true; } @@ -1126,9 +1181,8 @@ if(dbg_aux) bool CSerial::Putchar(Bit8u data, bool wait_dsr, bool wait_cts, Bitu timeout) { double starttime=PIC_FullIndex(); - //Bit16u starttime= // wait for it to become empty - while(!(LSR&0x20)) { + while(!(Read_LSR()&0x20)) { CALLBACK_Idle(); } // wait for DSR+CTS on @@ -1142,13 +1196,10 @@ bool CSerial::Putchar(Bit8u data, bool wait_dsr, bool wait_cts, Bitu timeout) { } else if(wait_cts) { while(!(Read_MSR()&0x10)&&(starttime>PIC_FullIndex()-timeout)) CALLBACK_Idle(); - } if(!(starttime>PIC_FullIndex()-timeout)) { #if SERIAL_DEBUG - if(dbg_aux) - fprintf(debugfp,"%12.3f Putchar timeout: MSR 0x%x\r\n", - PIC_FullIndex(),Read_MSR()); + log_ser(dbg_aux,"Putchar timeout: MSR 0x%x",Read_MSR()); #endif return false; } @@ -1156,8 +1207,7 @@ bool CSerial::Putchar(Bit8u data, bool wait_dsr, bool wait_cts, Bitu timeout) { Write_THR(data); #if SERIAL_DEBUG - if(dbg_aux) - fprintf(debugfp,"%12.3f API write success: 0x%x\r\n", PIC_FullIndex(),data); + log_ser(dbg_aux,"Putchar 0x%x",data); #endif return true; diff --git a/src/hardware/serialport/softmodem.h b/src/hardware/serialport/softmodem.h index f30d746b..7cd1e792 100644 --- a/src/hardware/serialport/softmodem.h +++ b/src/hardware/serialport/softmodem.h @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: softmodem.h,v 1.10 2009-05-27 09:15:42 qbix79 Exp $ */ +/* $Id: softmodem.h,v 1.11 2009-09-25 23:40:47 h-a-l-9000 Exp $ */ #ifndef DOSBOX_SERIALMODEM_H #define DOSBOX_SERIALMODEM_H @@ -92,7 +92,7 @@ public: static Bits lcount=0; if (lcount<1000) { lcount++; - LOG_MSG("MODEM: FIFO Overflow! (adds len %d)",_len); + LOG_MSG("MODEM: FIFO Overflow! (adds len %u)",_len); } return; } diff --git a/visualc_net/dosbox.vcproj b/visualc_net/dosbox.vcproj index 43a487d1..5a36f2ef 100644 --- a/visualc_net/dosbox.vcproj +++ b/visualc_net/dosbox.vcproj @@ -309,10 +309,10 @@ RelativePath="..\src\cpu\core_dynrec\operators.h"> + RelativePath="..\src\cpu\core_dynrec\risc_x64.h"> + RelativePath="..\src\cpu\core_dynrec\risc_x86.h"> @@ -567,28 +567,16 @@ Name="serialport" Filter=""> - - - + RelativePath="..\src\hardware\serialport\directserial.cpp"> + RelativePath="..\src\hardware\serialport\directserial.h"> + RelativePath="..\src\hardware\serialport\libserial.cpp"> - - - - + RelativePath="..\src\hardware\serialport\libserial.h"> @@ -622,6 +610,9 @@ + + @@ -649,9 +640,6 @@ - -