DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
include/serialport.h
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #ifndef DOSBOX_SERIALPORT_H
00021 #define DOSBOX_SERIALPORT_H
00022 
00023 #ifndef DOSBOX_DOSBOX_H
00024 #include "dosbox.h"
00025 #endif
00026 #ifndef DOSBOX_INOUT_H
00027 #include "inout.h"
00028 #endif
00029 #ifndef DOSBOX_TIMER_H
00030 #include "timer.h"
00031 #endif
00032 #ifndef DOSBOX_DOS_INC_H
00033 #include "dos_inc.h"
00034 #endif
00035 #ifndef DOSBOX_PROGRAMS_H
00036 #include "programs.h"
00037 #endif
00038 
00039 // set this to 1 for serial debugging in release mode
00040 #define SERIAL_DBG_FORCED 1
00041 
00042 #if (C_DEBUG || SERIAL_DBG_FORCED)
00043 #define SERIAL_DEBUG 1
00044 #endif
00045 
00046 #if SERIAL_DEBUG
00047 #include "hardware.h"
00048 #endif
00049 
00050 // Serial port interface 
00051 
00052 class MyFifo {
00053 public:
00054         MyFifo(Bitu maxsize_) {
00055                 maxsize=size=maxsize_;
00056                 pos=used=0;
00057                 data=new Bit8u[size];
00058         }
00059         ~MyFifo() {
00060                 if (data != NULL) {
00061                         delete[] data;
00062                         data = NULL;
00063                 }
00064         }
00065         INLINE Bitu getFree(void) {
00066                 return size-used;
00067         }
00068         bool isEmpty() {
00069                 return used==0;
00070         }
00071         bool isFull() {
00072                 return (size-used)==0;
00073         }
00074 
00075         INLINE Bitu getUsage(void) {
00076                 return used;
00077         }
00078         void setSize(Bitu newsize)
00079         {
00080                 size=newsize;
00081                 pos=used=0;
00082         }
00083         void clear(void) {
00084                 pos=used=0;
00085                 data[0]=0;
00086         }
00087 
00088         bool addb(Bit8u _val) {
00089                 Bitu where=pos+used;
00090                 if (where>=size) where-=size;
00091                 if(used>=size) {
00092                         // overwrite last byte
00093                         if(where==0) where=size-1;
00094                         else where--;
00095                         data[where]=_val;
00096                         return false;
00097                 }
00098                 data[where]=_val;
00099                 used++;
00100                 return true;
00101         }
00102         Bit8u getb() {
00103                 if (!used) return data[pos];
00104                 Bitu where=pos;
00105                 used--;
00106                 if(used) pos++;
00107                 if (pos>=size) pos-=size;
00108                 return data[where];
00109         }
00110         Bit8u getTop() {
00111                 Bitu where=pos+used;
00112                 if (where>=size) where-=size;
00113                 if(used>=size) {
00114                         if(where==0) where=size-1;
00115                         else where--;
00116                 }
00117                 return data[where];
00118         }
00119 
00120         Bit8u probeByte() {
00121                 return data[pos];
00122         }
00123 private:
00124         Bit8u * data;
00125         Bitu maxsize,size,pos,used;
00126 };
00127 
00128 class CSerial {
00129 public:
00130 
00131 #if SERIAL_DEBUG
00132         FILE * debugfp;
00133         bool dbg_modemcontrol; // RTS,CTS,DTR,DSR,RI,CD
00134         bool dbg_serialtraffic;
00135         bool dbg_register;
00136         bool dbg_interrupt;
00137         bool dbg_aux;
00138         void log_ser(bool active, char const* format,...);
00139 #endif
00140 
00141         static bool getBituSubstring(const char* name,Bitu* data, CommandLine* cmd);
00142 
00143         bool InstallationSuccessful;// check after constructing. If
00144                                                                 // something was wrong, delete it right away.
00145 
00146         // Constructor takes com port number (0-3)
00147         CSerial(Bitu id, CommandLine* cmd);
00148         
00149         virtual ~CSerial();
00150                 
00151         IO_ReadHandleObject ReadHandler[8];
00152         IO_WriteHandleObject WriteHandler[8];
00153 
00154         float bytetime; // how long a byte takes to transmit/receive in milliseconds
00155         void changeLineProperties();
00156         Bitu idnumber;
00157 
00158         void setEvent(Bit16u type, float duration);
00159         void removeEvent(Bit16u type);
00160         void handleEvent(Bit16u type);
00161         virtual void handleUpperEvent(Bit16u type)=0;
00162         
00163         // defines for event type
00164 #define SERIAL_TX_LOOPBACK_EVENT 0
00165 #define SERIAL_THR_LOOPBACK_EVENT 1
00166 #define SERIAL_ERRMSG_EVENT 2
00167 
00168 #define SERIAL_TX_EVENT 3
00169 #define SERIAL_RX_EVENT 4
00170 #define SERIAL_POLLING_EVENT 5
00171 #define SERIAL_THR_EVENT 6
00172 #define SERIAL_RX_TIMEOUT_EVENT 7
00173 
00174 #define SERIAL_BASE_EVENT_COUNT 7
00175 
00176 #define COMNUMBER idnumber+1
00177 
00178         Bitu irq;
00179         
00180         // CSerial requests an update of the input lines
00181         virtual void updateMSR()=0;
00182 
00183         // Control lines from prepherial to serial port
00184         bool getDTR();
00185         bool getRTS();
00186 
00187         bool getRI();
00188         bool getCD();
00189         bool getDSR();
00190         bool getCTS();
00191 
00192         void setRI(bool value);
00193         void setDSR(bool value);
00194         void setCD(bool value);
00195         void setCTS(bool value);
00196 
00197         // From serial port to prepherial
00198         // set output lines
00199         virtual void setRTSDTR(bool rts, bool dtr)=0;
00200         virtual void setRTS(bool val)=0;
00201         virtual void setDTR(bool val)=0;
00202 
00203         // Register access
00204         void Write_THR(Bit8u data);
00205         void Write_IER(Bit8u data);
00206         void Write_FCR(Bit8u data);
00207         void Write_LCR(Bit8u data);
00208         void Write_MCR(Bit8u data);
00209         // Really old hardware seems to have the delta part of this register writable
00210         void Write_MSR(Bit8u val);
00211         void Write_SPR(Bit8u data);
00212         void Write_reserved(Bit8u data, Bit8u address);
00213 
00214         Bitu Read_RHR();
00215         Bitu Read_IER();
00216         Bitu Read_ISR();
00217         Bitu Read_LCR();
00218         Bitu Read_MCR();
00219         Bitu Read_LSR();
00220         Bitu Read_MSR();
00221         Bitu Read_SPR();
00222         
00223         // If a byte comes from loopback or prepherial, put it in here.
00224         void receiveByte(Bit8u data);
00225         void receiveByteEx(Bit8u data, Bit8u error);
00226 
00227         // depratched
00228         // connected device checks, if port can receive data:
00229         bool CanReceiveByte();
00230         
00231         // when THR was shifted to TX
00232         void ByteTransmitting();
00233         
00234         // When done sending, notify here
00235         void ByteTransmitted();
00236 
00237         // Transmit byte to prepherial
00238         virtual void transmitByte(Bit8u val, bool first)=0;
00239 
00240         // switch break state to the passed value
00241         virtual void setBreak(bool value)=0;
00242         
00243         // change baudrate, number of bits, parity, word length al at once
00244         virtual void updatePortConfig(Bit16u divider, Bit8u lcr)=0;
00245         
00246         void Init_Registers();
00247         
00248         bool Putchar(Bit8u data, bool wait_dsr, bool wait_cts, Bitu timeout);
00249         bool Getchar(Bit8u* data, Bit8u* lsr, bool wait_dsr, Bitu timeout);
00250 
00251         DOS_Device* mydosdevice;
00252 
00253         void registerDOSDevice();
00254         void unregisterDOSDevice();
00255 
00256 private:
00257 
00258         // I used this spec: st16c450v420.pdf
00259 
00260         void ComputeInterrupts();
00261         
00262         // a sub-interrupt is triggered
00263         void rise(Bit8u priority);
00264 
00265         // clears the pending sub-interrupt
00266         void clear(Bit8u priority);
00267         
00268         #define ERROR_PRIORITY 4        // overrun, parity error, frame error, break
00269         #define RX_PRIORITY 1           // a byte has been received
00270         #define TX_PRIORITY 2           // tx buffer has become empty
00271         #define MSR_PRIORITY 8          // CRS, DSR, RI, DCD change 
00272         #define TIMEOUT_PRIORITY 0x10
00273         #define NONE_PRIORITY 0
00274 
00275         Bit8u waiting_interrupts;       // these are on, but maybe not enabled
00276         
00277         // 16C550
00278         //                              read/write              name
00279 
00280         Bit16u baud_divider;
00281         #define RHR_OFFSET 0    // r Receive Holding Register, also LSB of Divisor Latch (r/w)
00282                                                         // Data: whole byte
00283         #define THR_OFFSET 0    // w Transmit Holding Register
00284                                                         // Data: whole byte
00285         Bit8u IER;      //      r/w             Interrupt Enable Register, also MSB of Divisor Latch
00286         #define IER_OFFSET 1
00287 
00288         bool irq_active;
00289                                 
00290         #define RHR_INT_Enable_MASK                             0x1
00291         #define THR_INT_Enable_MASK                             0x2
00292         #define Receive_Line_INT_Enable_MASK    0x4
00293         #define Modem_Status_INT_Enable_MASK    0x8
00294 
00295         Bit8u ISR;      //      r                               Interrupt Status Register
00296         #define ISR_OFFSET 2
00297 
00298         #define ISR_CLEAR_VAL 0x1
00299         #define ISR_FIFOTIMEOUT_VAL 0xc
00300         #define ISR_ERROR_VAL 0x6
00301         #define ISR_RX_VAL 0x4
00302         #define ISR_TX_VAL 0x2
00303         #define ISR_MSR_VAL 0x0
00304 public: 
00305         Bit8u LCR;      //      r/w                             Line Control Register
00306 private:
00307         #define LCR_OFFSET 3
00308                                                 // bit0: word length bit0
00309                                                 // bit1: word length bit1
00310                                                 // bit2: stop bits
00311                                                 // bit3: parity enable
00312                                                 // bit4: even parity
00313                                                 // bit5: set parity
00314                                                 // bit6: set break
00315                                                 // bit7: divisor latch enable
00316 
00317         
00318         #define LCR_BREAK_MASK 0x40
00319         #define LCR_DIVISOR_Enable_MASK 0x80
00320         #define LCR_PORTCONFIG_MASK 0x3F
00321         
00322         #define LCR_PARITY_NONE         0x0
00323         #define LCR_PARITY_ODD          0x8
00324         #define LCR_PARITY_EVEN         0x18
00325         #define LCR_PARITY_MARK         0x28
00326         #define LCR_PARITY_SPACE        0x38
00327 
00328         #define LCR_DATABITS_5          0x0
00329         #define LCR_DATABITS_6          0x1
00330         #define LCR_DATABITS_7          0x2
00331         #define LCR_DATABITS_8          0x3
00332 
00333         #define LCR_STOPBITS_1          0x0
00334         #define LCR_STOPBITS_MORE_THAN_1 0x4
00335 
00336         // Modem Control Register
00337         // r/w                          
00338         #define MCR_OFFSET 4
00339         bool dtr;                       // bit0: DTR
00340         bool rts;                       // bit1: RTS
00341         bool op1;                       // bit2: OP1
00342         bool op2;                       // bit3: OP2
00343         bool loopback;          // bit4: loop back enable
00344 
00345         #define MCR_DTR_MASK 0x1
00346         #define MCR_RTS_MASK 0x2        
00347         #define MCR_OP1_MASK 0x4        
00348         #define MCR_OP2_MASK 0x8
00349         #define MCR_LOOPBACK_Enable_MASK 0x10
00350 public: 
00351         Bit8u LSR;      //      r                               Line Status Register
00352 private:
00353 
00354         #define LSR_OFFSET 5
00355 
00356         #define LSR_RX_DATA_READY_MASK 0x1
00357         #define LSR_OVERRUN_ERROR_MASK 0x2
00358         #define LSR_PARITY_ERROR_MASK 0x4
00359         #define LSR_FRAMING_ERROR_MASK 0x8
00360         #define LSR_RX_BREAK_MASK 0x10
00361         #define LSR_TX_HOLDING_EMPTY_MASK 0x20
00362         #define LSR_TX_EMPTY_MASK 0x40
00363 
00364         #define LSR_ERROR_MASK 0x1e
00365 
00366         // error printing
00367         bool errormsg_pending;
00368         Bitu framingErrors;
00369         Bitu parityErrors;
00370         Bitu overrunErrors;
00371         Bitu txOverrunErrors;
00372         Bitu overrunIF0;
00373         Bitu breakErrors;
00374 
00375 
00376         // Modem Status Register
00377         //      r
00378         #define MSR_OFFSET 6
00379         bool d_cts;                     // bit0: deltaCTS
00380         bool d_dsr;                     // bit1: deltaDSR
00381         bool d_ri;                      // bit2: deltaRI
00382         bool d_cd;                      // bit3: deltaCD
00383         bool cts;                       // bit4: CTS
00384         bool dsr;                       // bit5: DSR
00385         bool ri;                        // bit6: RI
00386         bool cd;                        // bit7: CD
00387         
00388         #define MSR_delta_MASK 0xf
00389         #define MSR_LINE_MASK 0xf0
00390 
00391         #define MSR_dCTS_MASK 0x1
00392         #define MSR_dDSR_MASK 0x2
00393         #define MSR_dRI_MASK 0x4
00394         #define MSR_dCD_MASK 0x8
00395         #define MSR_CTS_MASK 0x10
00396         #define MSR_DSR_MASK 0x20
00397         #define MSR_RI_MASK 0x40
00398         #define MSR_CD_MASK 0x80
00399 
00400         Bit8u SPR;      //      r/w                             Scratchpad Register
00401         #define SPR_OFFSET 7
00402 
00403 
00404         // For loopback purposes...
00405         Bit8u loopback_data;
00406         void transmitLoopbackByte(Bit8u val, bool value);
00407 
00408         // 16C550 (FIFO)
00409         public: // todo remove
00410         MyFifo* rxfifo;
00411         private:
00412         MyFifo* txfifo;
00413         MyFifo* errorfifo;
00414         Bitu errors_in_fifo;
00415         Bitu rx_interrupt_threshold;
00416         Bitu fifosize;
00417         Bit8u FCR;
00418         bool sync_guardtime;
00419         #define FIFO_STATUS_ACTIVE 0xc0 // FIFO is active AND works ;)
00420         #define FIFO_ERROR 0x80
00421         #define FCR_ACTIVATE 0x01
00422         #define FCR_CLEAR_RX 0x02
00423         #define FCR_CLEAR_TX 0x04
00424         #define FCR_OFFSET 2
00425         #define FIFO_FLOWCONTROL 0x20
00426 };
00427 
00428 extern CSerial* serialports[];
00429 const Bit8u serial_defaultirq[] = { 4, 3, 4, 3 };
00430 const Bit16u serial_baseaddr[] = {0x3f8,0x2f8,0x3e8,0x2e8};
00431 const char* const serial_comname[]={"COM1","COM2","COM3","COM4"};
00432 
00433 // the COM devices
00434 
00435 class device_COM : public DOS_Device {
00436 public:
00437         // Creates a COM device that communicates with the num-th parallel port, i.e. is LPTnum
00438         device_COM(class CSerial* sc);
00439         virtual ~device_COM();
00440         bool Read(Bit8u * data,Bit16u * size);
00441         bool Write(const Bit8u * data,Bit16u * size);
00442         bool Seek(Bit32u * pos,Bit32u type);
00443         bool Close();
00444         Bit16u GetInformation(void);
00445 private:
00446         CSerial* sclass;
00447 };
00448 
00449 #endif