Add patch 1151453 from h-a-l-9000. Improves softmodem and directserial supports. Adds a dummy serial class as well and makes the serial ports runtime changable
Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@2257
This commit is contained in:
parent
4b6fd3c481
commit
a5252330f7
19 changed files with 3329 additions and 1484 deletions
|
@ -16,146 +16,283 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* $Id: serialport.h,v 1.9 2005-07-30 14:41:30 qbix79 Exp $ */
|
||||
|
||||
#ifndef DOSBOX_SERIALPORT_H
|
||||
#define DOSBOX_SERIALPORT_H
|
||||
|
||||
#include <assert.h>
|
||||
// Uncomment this for a lot of debug messages:
|
||||
//#define SERIALPORT_DEBUGMSG
|
||||
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#include "dosbox.h"
|
||||
#include "dosbox.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_INOUT_H
|
||||
#include "inout.h"
|
||||
#include "inout.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_TIMER_H
|
||||
#include "timer.h"
|
||||
#endif
|
||||
|
||||
//If it's too high you overflow terminal clients buffers i think
|
||||
#define QUEUE_SIZE 1024
|
||||
|
||||
// Serial port interface //
|
||||
|
||||
#define MS_CTS 0x01
|
||||
#define MS_DSR 0x02
|
||||
#define MS_RI 0x04
|
||||
#define MS_DCD 0x08
|
||||
|
||||
#define MC_DTR 0x1
|
||||
#define MC_RTS 0x2
|
||||
|
||||
|
||||
class CFifo {
|
||||
public:
|
||||
CFifo(Bitu _size) {
|
||||
size=_size;
|
||||
pos=used=0;
|
||||
data=new Bit8u[size];
|
||||
}
|
||||
~CFifo() {
|
||||
delete[] data;
|
||||
}
|
||||
INLINE Bitu left(void) {
|
||||
return size-used;
|
||||
}
|
||||
INLINE Bitu inuse(void) {
|
||||
return used;
|
||||
}
|
||||
void clear(void) {
|
||||
used=pos=0;
|
||||
}
|
||||
bool isFull() {
|
||||
return (used >= size);
|
||||
}
|
||||
void addb(Bit8u _val) {
|
||||
assert(used<size);
|
||||
Bitu where=pos+used;
|
||||
if (where>=size) where-=size;
|
||||
data[where]=_val;
|
||||
used++;
|
||||
}
|
||||
void adds(Bit8u * _str,Bitu _len) {
|
||||
assert((used+_len)<=size);
|
||||
Bitu where=pos+used;
|
||||
used+=_len;
|
||||
while (_len--) {
|
||||
if (where>=size) where-=size;
|
||||
data[where++]=*_str++;
|
||||
}
|
||||
}
|
||||
Bit8u getb(void) {
|
||||
if (!used) return data[pos];
|
||||
Bitu where=pos;
|
||||
if (++pos>=size) pos-=size;
|
||||
used--;
|
||||
return data[where];
|
||||
}
|
||||
void gets(Bit8u * _str,Bitu _len) {
|
||||
assert(used>=_len);
|
||||
used-=_len;
|
||||
while (_len--) {
|
||||
*_str++=data[pos];
|
||||
if (++pos>=size) pos-=size;
|
||||
}
|
||||
}
|
||||
private:
|
||||
Bit8u * data;
|
||||
Bitu size,pos,used;
|
||||
};
|
||||
|
||||
class CSerial {
|
||||
public:
|
||||
|
||||
CSerial() {
|
||||
|
||||
}
|
||||
// Constructor takes base port (0x3f0, 0x2f0, 0x2e0, etc.), IRQ, and initial bps //
|
||||
CSerial (Bit16u initbase, Bit8u initirq, Bit32u initbps);
|
||||
// Constructor takes base port (0x3f8, 0x2f8, 0x2e8, etc.), IRQ, and initial bps //
|
||||
CSerial(IO_ReadHandler* rh, IO_WriteHandler* wh,
|
||||
TIMER_TickHandler TimerHandler,
|
||||
Bit16u initbase, Bit8u initirq, Bit32u initbps,
|
||||
Bit8u bytesize, const char* parity, Bit8u stopbits);
|
||||
|
||||
TIMER_TickHandler TimerHnd;
|
||||
virtual ~CSerial();
|
||||
|
||||
IO_ReadHandleObject ReadHandler[8];
|
||||
IO_WriteHandleObject WriteHandler[8];
|
||||
|
||||
void write_reg(Bitu reg, Bitu val);
|
||||
Bitu read_reg(Bitu reg);
|
||||
|
||||
void SetModemStatus(Bit8u status);
|
||||
virtual bool CanRecv(void)=0;
|
||||
virtual bool CanSend(void)=0;
|
||||
virtual void Send(Bit8u val)=0;
|
||||
virtual Bit8u Recv(Bit8u val)=0;
|
||||
virtual void Timer(void);
|
||||
|
||||
void checkint(void);
|
||||
|
||||
void Timer(void);
|
||||
virtual void Timer2(void)=0;
|
||||
|
||||
Bitu base;
|
||||
Bitu irq;
|
||||
Bitu bps;
|
||||
Bit8u mctrl;
|
||||
|
||||
bool CSerial::getDTR();
|
||||
bool CSerial::getRTS();
|
||||
|
||||
CFifo *rqueue;
|
||||
CFifo *tqueue;
|
||||
bool CSerial::getRI();
|
||||
bool CSerial::getCD();
|
||||
bool CSerial::getDSR();
|
||||
bool CSerial::getCTS();
|
||||
|
||||
void CSerial::setRI(bool value);
|
||||
void CSerial::setDSR(bool value);
|
||||
void CSerial::setCD(bool value);
|
||||
void CSerial::setCTS(bool value);
|
||||
|
||||
void CSerial::Write_THR(Bit8u data);
|
||||
Bitu CSerial::Read_RHR();
|
||||
Bitu CSerial::Read_IER();
|
||||
void CSerial::Write_IER(Bit8u data);
|
||||
Bitu CSerial::Read_ISR();
|
||||
Bitu CSerial::Read_LCR();
|
||||
void CSerial::Write_LCR(Bit8u data);
|
||||
Bitu CSerial::Read_MCR();
|
||||
void CSerial::Write_MCR(Bit8u data);
|
||||
Bitu CSerial::Read_LSR();
|
||||
|
||||
// Really old hardware seems to have the delta part of this register writable
|
||||
void CSerial::Write_MSR(Bit8u data);
|
||||
|
||||
Bitu CSerial::Read_MSR();
|
||||
Bitu CSerial::Read_SPR();
|
||||
void CSerial::Write_SPR(Bit8u data);
|
||||
void CSerial::Write_reserved(Bit8u data, Bit8u address);
|
||||
|
||||
// If a byte comes from wherever(loopback or real port or maybe
|
||||
// that softmodem thingy), put it in here.
|
||||
void CSerial::receiveByte(Bit8u data);
|
||||
|
||||
// If an error was received, put it here (in LSR register format)
|
||||
void CSerial::receiveError(Bit8u errorword);
|
||||
|
||||
// connected device checks, if port can receive data:
|
||||
bool CSerial::CanReceiveByte();
|
||||
|
||||
// When done sending, notify here
|
||||
void CSerial::ByteTransmitted();
|
||||
|
||||
// Virtual app has read the received data
|
||||
virtual void RXBufferEmpty()=0;
|
||||
|
||||
// real transmit
|
||||
virtual void transmitByte(Bit8u val)=0;
|
||||
|
||||
// switch break state to the passed value
|
||||
virtual void setBreak(bool value)=0;
|
||||
|
||||
// set output lines
|
||||
virtual void updateModemControlLines(/*Bit8u mcr*/)=0;
|
||||
|
||||
// change baudrate, number of bits, parity, word length al at once
|
||||
virtual void updatePortConfig(Bit8u dll, Bit8u dlm, Bit8u lcr)=0;
|
||||
|
||||
// CSerial requests an update of the input lines
|
||||
virtual void updateMSR()=0;
|
||||
|
||||
// after update request, or some "real" changes,
|
||||
// modify MSR here
|
||||
void CSerial::changeMSR(Bit8u data); // make public
|
||||
|
||||
void CSerial::Init_Registers(Bit32u initbps,
|
||||
Bit8u bytesize, const char* parity, Bit8u stopbits);
|
||||
|
||||
private:
|
||||
void UpdateBaudrate(void);
|
||||
bool FIFOenabled;
|
||||
Bit8u FIFOsize;
|
||||
bool dotxint;
|
||||
|
||||
Bit8u scratch;
|
||||
Bit8u dlab;
|
||||
Bit8u divisor_lsb;
|
||||
Bit8u divisor_msb;
|
||||
Bit8u local_loopback;
|
||||
Bit8u iir;
|
||||
Bit8u ier;
|
||||
Bit8u mstatus;
|
||||
|
||||
Bit8u linectrl;
|
||||
Bit8u errors;
|
||||
IO_ReadHandleObject ReadHandler[9];
|
||||
IO_WriteHandleObject WriteHandler[9];
|
||||
// I used this spec: http://www.exar.com/products/st16c450v420.pdf
|
||||
|
||||
void CSerial::changeMSR_Loopback(Bit8u data);
|
||||
|
||||
void CSerial::WriteRealIER(Bit8u data);
|
||||
// reason for an interrupt has occured - functions triggers interrupt
|
||||
// if it is enabled and no higher-priority irq pending
|
||||
void CSerial::rise(Bit8u priority);
|
||||
|
||||
// clears the pending interrupt
|
||||
void CSerial::clear(Bit8u priority);
|
||||
|
||||
#define ERROR_PRIORITY 4 // overrun, parity error, frame error, break
|
||||
#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 NONE_PRIORITY 0
|
||||
|
||||
|
||||
Bit8u pending_interrupts; // stores triggered interupts
|
||||
Bit8u current_priority;
|
||||
Bit8u waiting_interrupts; // these are on, but maybe not enabled
|
||||
|
||||
// 16C450 (no FIFO)
|
||||
// read/write name
|
||||
|
||||
|
||||
Bit8u DLL; // r Baudrate divider low byte
|
||||
Bit8u DLM; // r "" high byte
|
||||
|
||||
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 (r/w)
|
||||
#define IER_OFFSET 1
|
||||
// Data:
|
||||
// bit0 receive holding register
|
||||
// bit1 transmit holding register
|
||||
// bit2 receive line status interrupt
|
||||
// bit3 modem status interrupt
|
||||
|
||||
#define RHR_INT_Enable_MASK 0x1
|
||||
#define THR_INT_Enable_MASK 0x2
|
||||
#define Receive_Line_INT_Enable_MASK 0x4
|
||||
#define Modem_Status_INT_Enable_MASK 0x8
|
||||
|
||||
Bit8u ISR; // r Interrupt Status Register
|
||||
#define ISR_OFFSET 2
|
||||
|
||||
#define ISR_CLEAR_VAL 0x1
|
||||
#define ISR_ERROR_VAL 0x6
|
||||
#define ISR_RX_VAL 0x4
|
||||
#define ISR_TX_VAL 0x2
|
||||
#define ISR_MSR_VAL 0x0
|
||||
public:
|
||||
Bit8u LCR; // r/w Line Control Register
|
||||
private:
|
||||
#define LCR_OFFSET 3
|
||||
// bit0: word length bit0
|
||||
// bit1: word length bit1
|
||||
// bit2: stop bits
|
||||
// bit3: parity enable
|
||||
// bit4: even parity
|
||||
// bit5: set parity
|
||||
// bit6: set break
|
||||
// bit7: divisor latch enable
|
||||
|
||||
|
||||
#define LCR_BREAK_MASK 0x40
|
||||
#define LCR_DIVISOR_Enable_MASK 0x80
|
||||
#define LCR_PORTCONFIG_MASK 0x3F
|
||||
|
||||
#define LCR_PARITY_NONE 0x0
|
||||
#define LCR_PARITY_ODD 0x8
|
||||
#define LCR_PARITY_EVEN 0x18
|
||||
#define LCR_PARITY_MARK 0x28
|
||||
#define LCR_PARITY_SPACE 0x38
|
||||
|
||||
#define LCR_DATABITS_5 0x0
|
||||
#define LCR_DATABITS_6 0x1
|
||||
#define LCR_DATABITS_7 0x2
|
||||
#define LCR_DATABITS_8 0x3
|
||||
|
||||
#define LCR_STOPBITS_1 0x0
|
||||
#define LCR_STOPBITS_MORE_THAN_1 0x4
|
||||
|
||||
Bit8u MCR; // r/w Modem Control Register
|
||||
#define MCR_OFFSET 4
|
||||
// bit0: DTR
|
||||
// bit1: RTS
|
||||
// bit2: OP1
|
||||
// bit3: OP2
|
||||
// bit4: loop back enable
|
||||
|
||||
#define MCR_LOOPBACK_Enable_MASK 0x10
|
||||
#define MCR_LEVELS_MASK 0xf
|
||||
|
||||
#define MCR_DTR_MASK 0x1
|
||||
#define MCR_RTS_MASK 0x2
|
||||
#define MCR_OP1_MASK 0x4
|
||||
#define MCR_OP2_MASK 0x8
|
||||
|
||||
Bit8u LSR; // r Line Status Register
|
||||
#define LSR_OFFSET 5
|
||||
|
||||
#define LSR_RX_DATA_READY_MASK 0x1
|
||||
#define LSR_OVERRUN_ERROR_MASK 0x2
|
||||
#define LSR_PARITY_ERROR_MASK 0x4
|
||||
#define LSR_FRAMING_ERROR_MASK 0x8
|
||||
#define LSR_RX_BREAK_MASK 0x10
|
||||
#define LSR_TX_HOLDING_EMPTY_MASK 0x20
|
||||
#define LSR_TX_EMPTY_MASK 0x40
|
||||
|
||||
#define LSR_ERROR_MASK 0x1e
|
||||
|
||||
|
||||
Bit8u MSR; // r Modem Status Register
|
||||
#define MSR_OFFSET 6
|
||||
// bit0: deltaCTS
|
||||
// bit1: deltaDSR
|
||||
// bit2: deltaRI
|
||||
// bit3: deltaCD
|
||||
// bit4: CTS
|
||||
// bit5: DSR
|
||||
// bit6: RI
|
||||
// bit7: CD
|
||||
|
||||
#define MSR_delta_MASK 0xf
|
||||
#define MSR_LINE_MASK 0xf0
|
||||
|
||||
#define MSR_dCTS_MASK 0x1
|
||||
#define MSR_dDSR_MASK 0x2
|
||||
#define MSR_dRI_MASK 0x4
|
||||
#define MSR_dCD_MASK 0x8
|
||||
#define MSR_CTS_MASK 0x10
|
||||
#define MSR_DSR_MASK 0x20
|
||||
#define MSR_RI_MASK 0x40
|
||||
#define MSR_CD_MASK 0x80
|
||||
|
||||
Bit8u SPR; // r/w Scratchpad Register
|
||||
#define SPR_OFFSET 7
|
||||
|
||||
|
||||
// For loopback purposes...
|
||||
bool loopback_pending;
|
||||
Bit8u loopback_data;
|
||||
void transmitLoopbackByte(Bit8u val);
|
||||
|
||||
// 16C550 (FIFO)
|
||||
// TODO
|
||||
//Bit8u FCR; // FIFO Control Register
|
||||
|
||||
};
|
||||
|
||||
#include <list>
|
||||
|
||||
typedef std::list<CSerial *> CSerialList;
|
||||
typedef std::list<CSerial *>::iterator CSerial_it;
|
||||
|
||||
extern CSerialList seriallist;
|
||||
#define COM1_BASE 0x3f8
|
||||
#define COM2_BASE 0x2f8
|
||||
#define COM3_BASE 0x3e8
|
||||
#define COM4_BASE 0x2e8
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue