1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
|
/*
* Copyright (C) 2002-2010 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: serialport.h,v 1.18 2009-09-25 23:40:48 h-a-l-9000 Exp $ */
#ifndef DOSBOX_SERIALPORT_H
#define DOSBOX_SERIALPORT_H
#ifndef DOSBOX_DOSBOX_H
#include "dosbox.h"
#endif
#ifndef DOSBOX_INOUT_H
#include "inout.h"
#endif
#ifndef DOSBOX_TIMER_H
#include "timer.h"
#endif
#ifndef DOSBOX_DOS_INC_H
#include "dos_inc.h"
#endif
#ifndef DOSBOX_PROGRAMS_H
#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;
used--;
if(used) pos++;
if (pos>=size) pos-=size;
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:
#if SERIAL_DEBUG
FILE * debugfp;
bool dbg_modemcontrol; // RTS,CTS,DTR,DSR,RI,CD
bool dbg_serialtraffic;
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);
bool InstallationSuccessful;// check after constructing. If
// something was wrong, delete it right away.
// Constructor takes com port number (0-3)
CSerial(Bitu id, CommandLine* cmd);
virtual ~CSerial();
IO_ReadHandleObject ReadHandler[8];
IO_WriteHandleObject WriteHandler[8];
float bytetime; // how long a byte takes to transmit/receive in milliseconds
void changeLineProperties();
Bitu idnumber;
void setEvent(Bit16u type, float duration);
void removeEvent(Bit16u type);
void handleEvent(Bit16u type);
virtual void handleUpperEvent(Bit16u type)=0;
// defines for event type
#define SERIAL_TX_LOOPBACK_EVENT 0
#define SERIAL_THR_LOOPBACK_EVENT 1
#define SERIAL_ERRMSG_EVENT 2
#define SERIAL_TX_EVENT 3
#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 7
#define COMNUMBER idnumber+1
Bitu irq;
// CSerial requests an update of the input lines
virtual void updateMSR()=0;
// Control lines from prepherial to serial port
bool getDTR();
bool getRTS();
bool getRI();
bool getCD();
bool getDSR();
bool getCTS();
void setRI(bool value);
void setDSR(bool value);
void setCD(bool value);
void setCTS(bool value);
// From serial port to prepherial
// set output lines
virtual void setRTSDTR(bool rts, bool dtr)=0;
virtual void setRTS(bool val)=0;
virtual void setDTR(bool val)=0;
// Register access
void Write_THR(Bit8u data);
void Write_IER(Bit8u data);
void Write_FCR(Bit8u data);
void Write_LCR(Bit8u data);
void Write_MCR(Bit8u data);
// Really old hardware seems to have the delta part of this register writable
void Write_MSR(Bit8u data);
void Write_SPR(Bit8u data);
void Write_reserved(Bit8u data, Bit8u address);
Bitu Read_RHR();
Bitu Read_IER();
Bitu Read_ISR();
Bitu Read_LCR();
Bitu Read_MCR();
Bitu Read_LSR();
Bitu Read_MSR();
Bitu Read_SPR();
// 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);
// depratched
// connected device checks, if port can receive data:
bool CanReceiveByte();
// when THR was shifted to TX
void ByteTransmitting();
// When done sending, notify here
void ByteTransmitted();
// Transmit byte to prepherial
virtual void transmitByte(Bit8u val, bool first)=0;
// switch break state to the passed value
virtual void setBreak(bool value)=0;
// change baudrate, number of bits, parity, word length al at once
virtual void updatePortConfig(Bit16u divider, Bit8u lcr)=0;
void Init_Registers();
bool Putchar(Bit8u data, bool wait_dtr, bool wait_rts, Bitu timeout);
bool Getchar(Bit8u* data, Bit8u* lsr, bool wait_dsr, Bitu timeout);
private:
DOS_Device* mydosdevice;
// I used this spec: st16c450v420.pdf
void ComputeInterrupts();
// a sub-interrupt is triggered
void rise(Bit8u priority);
// clears the pending sub-interrupt
void 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 TIMEOUT_PRIORITY 0x10
#define NONE_PRIORITY 0
Bit8u waiting_interrupts; // these are on, but maybe not enabled
// 16C550
// read/write name
Bit16u baud_divider;
#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;
#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_FIFOTIMEOUT_VAL 0xc
#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
// Modem Control Register
// r/w
#define MCR_OFFSET 4
bool dtr; // bit0: DTR
bool rts; // bit1: RTS
bool op1; // bit2: OP1
bool op2; // bit3: OP2
bool loopback; // bit4: loop back enable
#define MCR_DTR_MASK 0x1
#define MCR_RTS_MASK 0x2
#define MCR_OP1_MASK 0x4
#define MCR_OP2_MASK 0x8
#define MCR_LOOPBACK_Enable_MASK 0x10
public:
Bit8u LSR; // r Line Status Register
private:
#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
// error printing
bool errormsg_pending;
Bitu framingErrors;
Bitu parityErrors;
Bitu overrunErrors;
Bitu txOverrunErrors;
Bitu overrunIF0;
Bitu breakErrors;
// Modem Status Register
// r
#define MSR_OFFSET 6
bool d_cts; // bit0: deltaCTS
bool d_dsr; // bit1: deltaDSR
bool d_ri; // bit2: deltaRI
bool d_cd; // bit3: deltaCD
bool cts; // bit4: CTS
bool dsr; // bit5: DSR
bool ri; // bit6: RI
bool cd; // 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...
Bit8u loopback_data;
void transmitLoopbackByte(Bit8u val, bool value);
// 16C550 (FIFO)
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
#define FIFO_FLOWCONTROL 0x20
};
extern CSerial* serialports[];
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
class device_COM : public DOS_Device {
public:
// Creates a COM device that communicates with the num-th parallel port, i.e. is LPTnum
device_COM(class CSerial* sc);
~device_COM();
bool Read(Bit8u * data,Bit16u * size);
bool Write(Bit8u * data,Bit16u * size);
bool Seek(Bit32u * pos,Bit32u type);
bool Close();
Bit16u GetInformation(void);
private:
CSerial* sclass;
};
#endif
|