DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
include/serialport.h
00001 /*
00002  *  Copyright (C) 2002-2015  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
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 data);
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         // If an error was received, put it here (in LSR register format)
00228         void receiveError(Bit8u errorword);
00229 
00230         // depratched
00231         // connected device checks, if port can receive data:
00232         bool CanReceiveByte();
00233         
00234         // when THR was shifted to TX
00235         void ByteTransmitting();
00236         
00237         // When done sending, notify here
00238         void ByteTransmitted();
00239 
00240         // Transmit byte to prepherial
00241         virtual void transmitByte(Bit8u val, bool first)=0;
00242 
00243         // switch break state to the passed value
00244         virtual void setBreak(bool value)=0;
00245         
00246         // change baudrate, number of bits, parity, word length al at once
00247         virtual void updatePortConfig(Bit16u divider, Bit8u lcr)=0;
00248         
00249         void Init_Registers();
00250         
00251         bool Putchar(Bit8u data, bool wait_dtr, bool wait_rts, Bitu timeout);
00252         bool Getchar(Bit8u* data, Bit8u* lsr, bool wait_dsr, Bitu timeout);
00253 
00254         DOS_Device* mydosdevice;
00255 
00256         void registerDOSDevice();
00257         void unregisterDOSDevice();
00258 
00259 private:
00260 
00261         // I used this spec: st16c450v420.pdf
00262 
00263         void ComputeInterrupts();
00264         
00265         // a sub-interrupt is triggered
00266         void rise(Bit8u priority);
00267 
00268         // clears the pending sub-interrupt
00269         void clear(Bit8u priority);
00270         
00271         #define ERROR_PRIORITY 4        // overrun, parity error, frame error, break
00272         #define RX_PRIORITY 1           // a byte has been received
00273         #define TX_PRIORITY 2           // tx buffer has become empty
00274         #define MSR_PRIORITY 8          // CRS, DSR, RI, DCD change 
00275         #define TIMEOUT_PRIORITY 0x10
00276         #define NONE_PRIORITY 0
00277 
00278         Bit8u waiting_interrupts;       // these are on, but maybe not enabled
00279         
00280         // 16C550
00281         //                              read/write              name
00282 
00283         Bit16u baud_divider;
00284         #define RHR_OFFSET 0    // r Receive Holding Register, also LSB of Divisor Latch (r/w)
00285                                                         // Data: whole byte
00286         #define THR_OFFSET 0    // w Transmit Holding Register
00287                                                         // Data: whole byte
00288         Bit8u IER;      //      r/w             Interrupt Enable Register, also MSB of Divisor Latch
00289         #define IER_OFFSET 1
00290 
00291         bool irq_active;
00292                                 
00293         #define RHR_INT_Enable_MASK                             0x1
00294         #define THR_INT_Enable_MASK                             0x2
00295         #define Receive_Line_INT_Enable_MASK    0x4
00296         #define Modem_Status_INT_Enable_MASK    0x8
00297 
00298         Bit8u ISR;      //      r                               Interrupt Status Register
00299         #define ISR_OFFSET 2
00300 
00301         #define ISR_CLEAR_VAL 0x1
00302         #define ISR_FIFOTIMEOUT_VAL 0xc
00303         #define ISR_ERROR_VAL 0x6
00304         #define ISR_RX_VAL 0x4
00305         #define ISR_TX_VAL 0x2
00306         #define ISR_MSR_VAL 0x0
00307 public: 
00308         Bit8u LCR;      //      r/w                             Line Control Register
00309 private:
00310         #define LCR_OFFSET 3
00311                                                 // bit0: word length bit0
00312                                                 // bit1: word length bit1
00313                                                 // bit2: stop bits
00314                                                 // bit3: parity enable
00315                                                 // bit4: even parity
00316                                                 // bit5: set parity
00317                                                 // bit6: set break
00318                                                 // bit7: divisor latch enable
00319 
00320         
00321         #define LCR_BREAK_MASK 0x40
00322         #define LCR_DIVISOR_Enable_MASK 0x80
00323         #define LCR_PORTCONFIG_MASK 0x3F
00324         
00325         #define LCR_PARITY_NONE         0x0
00326         #define LCR_PARITY_ODD          0x8
00327         #define LCR_PARITY_EVEN         0x18
00328         #define LCR_PARITY_MARK         0x28
00329         #define LCR_PARITY_SPACE        0x38
00330 
00331         #define LCR_DATABITS_5          0x0
00332         #define LCR_DATABITS_6          0x1
00333         #define LCR_DATABITS_7          0x2
00334         #define LCR_DATABITS_8          0x3
00335 
00336         #define LCR_STOPBITS_1          0x0
00337         #define LCR_STOPBITS_MORE_THAN_1 0x4
00338 
00339         // Modem Control Register
00340         // r/w                          
00341         #define MCR_OFFSET 4
00342         bool dtr;                       // bit0: DTR
00343         bool rts;                       // bit1: RTS
00344         bool op1;                       // bit2: OP1
00345         bool op2;                       // bit3: OP2
00346         bool loopback;          // bit4: loop back enable
00347 
00348         #define MCR_DTR_MASK 0x1
00349         #define MCR_RTS_MASK 0x2        
00350         #define MCR_OP1_MASK 0x4        
00351         #define MCR_OP2_MASK 0x8
00352         #define MCR_LOOPBACK_Enable_MASK 0x10
00353 public: 
00354         Bit8u LSR;      //      r                               Line Status Register
00355 private:
00356 
00357         #define LSR_OFFSET 5
00358 
00359         #define LSR_RX_DATA_READY_MASK 0x1
00360         #define LSR_OVERRUN_ERROR_MASK 0x2
00361         #define LSR_PARITY_ERROR_MASK 0x4
00362         #define LSR_FRAMING_ERROR_MASK 0x8
00363         #define LSR_RX_BREAK_MASK 0x10
00364         #define LSR_TX_HOLDING_EMPTY_MASK 0x20
00365         #define LSR_TX_EMPTY_MASK 0x40
00366 
00367         #define LSR_ERROR_MASK 0x1e
00368 
00369         // error printing
00370         bool errormsg_pending;
00371         Bitu framingErrors;
00372         Bitu parityErrors;
00373         Bitu overrunErrors;
00374         Bitu txOverrunErrors;
00375         Bitu overrunIF0;
00376         Bitu breakErrors;
00377 
00378 
00379         // Modem Status Register
00380         //      r
00381         #define MSR_OFFSET 6
00382         bool d_cts;                     // bit0: deltaCTS
00383         bool d_dsr;                     // bit1: deltaDSR
00384         bool d_ri;                      // bit2: deltaRI
00385         bool d_cd;                      // bit3: deltaCD
00386         bool cts;                       // bit4: CTS
00387         bool dsr;                       // bit5: DSR
00388         bool ri;                        // bit6: RI
00389         bool cd;                        // bit7: CD
00390         
00391         #define MSR_delta_MASK 0xf
00392         #define MSR_LINE_MASK 0xf0
00393 
00394         #define MSR_dCTS_MASK 0x1
00395         #define MSR_dDSR_MASK 0x2
00396         #define MSR_dRI_MASK 0x4
00397         #define MSR_dCD_MASK 0x8
00398         #define MSR_CTS_MASK 0x10
00399         #define MSR_DSR_MASK 0x20
00400         #define MSR_RI_MASK 0x40
00401         #define MSR_CD_MASK 0x80
00402 
00403         Bit8u SPR;      //      r/w                             Scratchpad Register
00404         #define SPR_OFFSET 7
00405 
00406 
00407         // For loopback purposes...
00408         Bit8u loopback_data;
00409         void transmitLoopbackByte(Bit8u val, bool value);
00410 
00411         // 16C550 (FIFO)
00412         public: // todo remove
00413         MyFifo* rxfifo;
00414         private:
00415         MyFifo* txfifo;
00416         MyFifo* errorfifo;
00417         Bitu errors_in_fifo;
00418         Bitu rx_interrupt_threshold;
00419         Bitu fifosize;
00420         Bit8u FCR;
00421         bool sync_guardtime;
00422         #define FIFO_STATUS_ACTIVE 0xc0 // FIFO is active AND works ;)
00423         #define FIFO_ERROR 0x80
00424         #define FCR_ACTIVATE 0x01
00425         #define FCR_CLEAR_RX 0x02
00426         #define FCR_CLEAR_TX 0x04
00427         #define FCR_OFFSET 2
00428         #define FIFO_FLOWCONTROL 0x20
00429 };
00430 
00431 extern CSerial* serialports[];
00432 const Bit8u serial_defaultirq[] = { 4, 3, 4, 3 };
00433 const Bit16u serial_baseaddr[] = {0x3f8,0x2f8,0x3e8,0x2e8};
00434 const char* const serial_comname[]={"COM1","COM2","COM3","COM4"};
00435 
00436 // the COM devices
00437 
00438 class device_COM : public DOS_Device {
00439 public:
00440         // Creates a COM device that communicates with the num-th parallel port, i.e. is LPTnum
00441         device_COM(class CSerial* sc);
00442         virtual ~device_COM();
00443         bool Read(Bit8u * data,Bit16u * size);
00444         bool Write(const Bit8u * data,Bit16u * size);
00445         bool Seek(Bit32u * pos,Bit32u type);
00446         bool Close();
00447         Bit16u GetInformation(void);
00448 private:
00449         CSerial* sclass;
00450 };
00451 
00452 #endif