- 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:
		
							parent
							
								
									599de7a67f
								
							
						
					
					
						commit
						8115555a4a
					
				
					 18 changed files with 1834 additions and 1913 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										319
									
								
								src/hardware/serialport/directserial.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										319
									
								
								src/hardware/serialport/directserial.cpp
									
										
									
									
									
										Normal 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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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, ¶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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										706
									
								
								src/hardware/serialport/libserial.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										706
									
								
								src/hardware/serialport/libserial.cpp
									
										
									
									
									
										Normal 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,
 | 
			
		||||
		¶mline, ulParmLen, &ulParmLen, 0, 0, 0);
 | 
			
		||||
	if ( rc != NO_ERROR)
 | 
			
		||||
		return false;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										56
									
								
								src/hardware/serialport/libserial.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/hardware/serialport/libserial.h
									
										
									
									
									
										Normal 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);
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
											
										
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue