1
0
Fork 0

- add 16C550A FIFO support to the serial port

- timing improvements for directserial
- the platform specific part of directserial is now combined for less redundancy


Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@3472
This commit is contained in:
Ralf Grillenberger 2009-09-25 23:40:48 +00:00
parent 599de7a67f
commit 8115555a4a
18 changed files with 1834 additions and 1913 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 <winsock2.h> //To prevent compilation problems with windows.h including winsock.h
#include <windows.h>
#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

View file

@ -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 <os2.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;
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, &paramline, 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, &paramline, 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

View file

@ -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 <os2.h>
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

View file

@ -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 <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.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;
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

View file

@ -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 <termios.h>
#include <unistd.h>
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

View file

@ -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 <windows.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;
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

View file

@ -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 <windows.h>
#include <stdio.h>
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 <memory.h> // strlen
#include <malloc.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h> // 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 <os2.h>
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,
&paramline, ulParmLen, &ulParmLen, 0, 0, 0);
if ( rc != NO_ERROR)
return false;
return true;
}
#endif

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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();

File diff suppressed because it is too large Load diff

View file

@ -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;
}

View file

@ -309,10 +309,10 @@
RelativePath="..\src\cpu\core_dynrec\operators.h">
</File>
<File
RelativePath="..\src\cpu\core_dynrec\risc_x86.h">
RelativePath="..\src\cpu\core_dynrec\risc_x64.h">
</File>
<File
RelativePath="..\src\cpu\core_dynrec\risc_x64.h">
RelativePath="..\src\cpu\core_dynrec\risc_x86.h">
</File>
</Filter>
</Filter>
@ -567,28 +567,16 @@
Name="serialport"
Filter="">
<File
RelativePath="..\src\hardware\serialport\directserial_os2.cpp">
<FileConfiguration
Name="Release|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCLCompilerTool"/>
</FileConfiguration>
RelativePath="..\src\hardware\serialport\directserial.cpp">
</File>
<File
RelativePath="..\src\hardware\serialport\directserial_os2.h">
RelativePath="..\src\hardware\serialport\directserial.h">
</File>
<File
RelativePath="..\src\hardware\serialport\directserial_posix.cpp">
RelativePath="..\src\hardware\serialport\libserial.cpp">
</File>
<File
RelativePath="..\src\hardware\serialport\directserial_posix.h">
</File>
<File
RelativePath="..\src\hardware\serialport\directserial_win32.cpp">
</File>
<File
RelativePath="..\src\hardware\serialport\directserial_win32.h">
RelativePath="..\src\hardware\serialport\libserial.h">
</File>
<File
RelativePath="..\src\hardware\serialport\misc_util.cpp">
@ -622,6 +610,9 @@
<Filter
Name="gui"
Filter="">
<File
RelativePath="..\src\libs\gui_tk\gui_tk.cpp">
</File>
<File
RelativePath="..\src\gui\midi.cpp">
</File>
@ -649,9 +640,6 @@
<File
RelativePath="..\src\gui\sdlmain.cpp">
</File>
<File
RelativePath="..\src\libs\gui_tk\gui_tk.cpp">
</File>
</Filter>
<Filter
Name="ints"