diff --git a/include/serialport.h b/include/serialport.h new file mode 100644 index 00000000..9f08303a --- /dev/null +++ b/include/serialport.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2002 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 Library 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. + */ + +#if !defined __SERIALPORT_H +#define __SERIALPORT_H + +#include + +//If it's too high you overflow terminal clients buffers i think +#define FIFO_SIZE (1024) + +// Serial port interface // + +#define M_CTS 0x01 +#define M_DSR 0x02 +#define M_RI 0x04 +#define M_DCD 0x08 + +enum INT_TYPES { + INT_MS, + INT_TX, + INT_RX, + INT_RX_FIFO, + INT_LS, + INT_NONE, +}; + +typedef void MControl_Handler(Bitu mc); + +class CSerial { +public: + + // Constructor takes base port (0x3f0, 0x2f0, 0x2e0, etc.), IRQ, and initial bps // + CSerial (Bit16u initbase, Bit8u initirq, Bit32u initbps); + virtual ~CSerial(); + + // External port functions for IOHandlers // + void write_port(Bit32u port, Bit8u val); + Bit8u read_port(Bit32u port); + + static void write_serial(Bit32u port,Bit8u val); + static Bit8u read_serial(Bit32u port); + + void SetMCHandler(MControl_Handler * mcontrol); + + /* Allow the modem to change the modem status bits */ + void setmodemstatus(Bit8u status); + Bit8u getmodemstatus(void); + Bit8u getlinestatus(void); + + void checkint(void); + void raiseint(INT_TYPES type); + void lowerint(INT_TYPES type); + + /* Access to the receive fifo */ + Bitu rx_free(); + void rx_addb(Bit8u byte); + void rx_adds(Bit8u * data,Bitu size); + Bitu rx_size(); + Bit8u rx_readb(void); + + /* Access to the transmit fifo */ + Bitu tx_free(); + void tx_addb(Bit8u byte); + Bitu tx_size(); + Bit8u tx_readb(void); + + + // These variables maintain the status of the serial port + Bit16u base; + Bit16u irq; + Bit32u bps; + + bool FIFOenabled; + Bit16u FIFOsize; + +private: + + void setdivisor(Bit8u dmsb, Bit8u dlsb); + void checkforirq(void); + struct { + Bitu used; + Bitu pos; + Bit8u data[FIFO_SIZE]; + } rx_fifo,tx_fifo; + struct { + Bitu requested; + Bitu enabled; + INT_TYPES active; + } ints; + + Bitu rx_lastread; + Bit8u irq_pending; + + Bit8u scratch; + Bit8u dlab; + Bit8u divisor_lsb; + Bit8u divisor_msb; + Bit8u wordlen; + Bit8u dtr; + Bit8u rts; + Bit8u out1; + Bit8u out2; + Bit8u local_loopback; + Bit8u linectrl; + Bit8u intid; + Bit8u ierval; + Bit8u mstatus; + + Bit8u txval; + Bit8u timeout; + + MControl_Handler * mc_handler; + char remotestr[4096]; +}; + +// This function returns the CSerial objects for ports 1-4 // +CSerial *getComport(Bitu portnum); + +#endif \ No newline at end of file diff --git a/src/hardware/serialport.cpp b/src/hardware/serialport.cpp new file mode 100644 index 00000000..eb040151 --- /dev/null +++ b/src/hardware/serialport.cpp @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2002 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 Library 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. + */ + +#include +#include "sdl_syswm.h" + +#include "dosbox.h" +#include "inout.h" +#include "mixer.h" +#include "pic.h" +#include "setup.h" +#include "timer.h" +#include "math.h" +#include "regs.h" +#include "serialport.h" + +#define SERIALBASERATE 115200 +#define SERIALPORT_COUNT 2 + +#define LOG_UART LOG_MSG +CSerial *serialports[SERIALPORT_COUNT]; + + +void CSerial::setdivisor(Bit8u dmsb, Bit8u dlsb) { + Bitu divsize=(dmsb << 8) | dlsb; + if (divsize!=0) { + bps = SERIALBASERATE / divsize; + } +} + + +void CSerial::checkint(void) { + /* Find lowest priority interrupt to activate */ + Bitu i; + for (i=0;i> 6) { + case 0: + FIFOsize = 1; + break; + case 1: + FIFOsize = 4; + break; + case 2: + FIFOsize = 8; + break; + case 3: + FIFOsize = 14; + break; + } + break; + case 0xb: // Line control register + linectrl = val; + wordlen = (val & 0x3); + dlab = (val & 0x80) > 0; + break; + case 0xc: // Modem control register + dtr = val & 0x01; + rts = (val & 0x02) > 0 ; + out1 = (val & 0x04) > 0; + out2 = (val & 0x08) > 0; + if (mc_handler) (*mc_handler)(val & 0xf); + local_loopback = (val & 0x10) > 0; + break; + case 0xf: // Scratch register + scratch = val; + break; + default: + LOG_UART("Modem: Write to 0x%x, with 0x%x '%c'\n", port,val,val); + break; + } +} + +void CSerial::write_serial(Bit32u port, Bit8u val) { + int i; + + for(i=0;i=serialports[i]->base+0x8) && (port<=(serialports[i]->base+0xf)) ) { + serialports[i]->write_port(port,val); + } + } +} + +Bit8u CSerial::read_port(Bit32u port) { + Bit8u outval = 0; + + port-=base; +// LOG_MSG("Serial read form %X",port); + switch(port) { + case 0x8: // Receive buffer + Divisor LSB + if (dlab) { + return divisor_lsb ; + } else { + outval = rx_readb(); +// LOG_UART("Read from %X %X %c remain %d",port,outval,outval,rx_fifo.used); + return outval; + } + case 0x9: // Interrupt enable register + Divisor MSB + if (dlab) { + return divisor_msb ; + } else { +// LOG_UART("Read from %X %X",port,ierval); + return ierval; + } + case 0xa: // Interrupt identification register + switch (ints.active) { + case INT_MS: + outval = 0x0; + break; + case INT_TX: + outval = 0x2; + lowerint(INT_TX); + goto skipreset; + case INT_RX: + outval = 0x4; + break; + case INT_RX_FIFO: + lowerint(INT_RX_FIFO); + outval = 0xc; + goto skipreset; + case INT_LS: + outval = 0x6; + break; + case INT_NONE: + outval = 0x1; + break; + } + ints.active=INT_NONE; +skipreset: + if (FIFOenabled) outval |= 3 << 6; +// LOG_UART("Read from %X %X",port,outval); + return outval; + case 0xb: // Line control register + LOG_UART("Read from %X %X",port,outval); + return linectrl; + case 0xC: // Modem control register + outval = dtr | (rts << 1) | (out1 << 2) | (out2 << 3) | (local_loopback << 4); +// LOG_UART("Read from %X %X",port,outval); + return outval; + case 0xD: // Line status register + lowerint(INT_LS); + outval = 0x40; + if (FIFOenabled) { + if (!tx_fifo.used) outval|=0x20; + } else if (tx_fifo.used=serialports[i]->base+0x8) && (port<=(serialports[i]->base+0xf)) ) { + return serialports[i]->read_port(port); + } + } + return 0x00; +} + +Bitu CSerial::rx_free() { + return FIFO_SIZE-rx_fifo.used; +} + +Bitu CSerial::tx_free() { + return FIFO_SIZE-tx_fifo.used; +} + +Bitu CSerial::tx_size() { + if (FIFOenabled && rx_fifo.used && (rx_lastread < (PIC_Ticks-2))) { + raiseint(INT_RX_FIFO); + } + return tx_fifo.used; +} + +Bitu CSerial::rx_size() { + return rx_fifo.used; +} + +void CSerial::rx_addb(Bit8u data) { + LOG_UART("RX add %c",data); + if (rx_fifo.used=FIFO_SIZE) where-=FIFO_SIZE; + rx_fifo.data[where]=data; + rx_fifo.used++; + if (FIFOenabled && (rx_fifo.used < FIFOsize)) return; + /* Raise rx irq if possible */ + if (ints.active != INT_RX) raiseint(INT_RX); + } +} + +void CSerial::rx_adds(Bit8u * data,Bitu size) { + if ((rx_fifo.used+size)<=FIFO_SIZE) { + Bitu where=rx_fifo.pos+rx_fifo.used; + rx_fifo.used+=size; + while (size--) { + if (where>=FIFO_SIZE) where-=FIFO_SIZE; + rx_fifo.data[where++]=*data++; + } + if (FIFOenabled && (rx_fifo.used < FIFOsize)) return; + if (ints.active != INT_RX) raiseint(INT_RX); + } else LOG_MSG("WTF"); +} + +void CSerial::tx_addb(Bit8u data) { + LOG_UART("TX add %c",data); + if (tx_fifo.used=FIFO_SIZE) where-=FIFO_SIZE; + tx_fifo.data[where]=data; + tx_fifo.used++; + if (tx_fifo.used<(FIFO_SIZE-16)) { + /* Only generate FIFO irq's every 16 bytes */ + if (FIFOenabled && (tx_fifo.used & 0xf)) return; + raiseint(INT_TX); + } + } else { + LOG_MSG("tx addb"); + } +} + +Bit8u CSerial::rx_readb() { + if (rx_fifo.used) { + rx_lastread=PIC_Ticks; + Bit8u val=rx_fifo.data[rx_fifo.pos]; + rx_fifo.pos++; + if (rx_fifo.pos>=FIFO_SIZE) rx_fifo.pos-=FIFO_SIZE; + rx_fifo.used--; + //Don't care for FIFO Size + if (FIFOenabled || !rx_fifo.used) lowerint(INT_RX); + else raiseint(INT_RX); + return val; + } else { + LOG_MSG("WTF rx readb"); + return 0; + } +} + +Bit8u CSerial::tx_readb() { + if (tx_fifo.used) { + Bit8u val=tx_fifo.data[tx_fifo.pos]; + tx_fifo.pos++; + if (tx_fifo.pos>=FIFO_SIZE) tx_fifo.pos-=FIFO_SIZE; + tx_fifo.used--; + if (FIFOenabled && !tx_fifo.used) raiseint(INT_TX); + return val; + } else { + LOG_MSG("WTF tx readb"); + return 0; + } +} + + +void CSerial::setmodemstatus(Bit8u status) { + Bitu oldstatus=mstatus >> 4; + if(oldstatus ^ status ) { + mstatus=status << 4; + mstatus|=(oldstatus ^ status); + raiseint(INT_MS); + } +} + +Bit8u CSerial::getmodemstatus() { + return (mstatus >> 4); +} + +Bit8u CSerial::getlinestatus() { + return read_port(0xd); +} + + +void CSerial::SetMCHandler(MControl_Handler * mcontrol) { + mc_handler=mcontrol; +} + +CSerial::CSerial (Bit16u initbase, Bit8u initirq, Bit32u initbps) { + + int i; + Bit16u initdiv; + + base=initbase; + irq=initirq; + bps=initbps; + + mc_handler = 0; + tx_fifo.used = tx_fifo.pos = 0; + rx_fifo.used = rx_fifo.pos = 0; + + rx_lastread = PIC_Ticks; + linectrl = dtr = rts = out1 = out2 = 0; + local_loopback = 0; + ierval = 0; + ints.enabled=1 << INT_RX_FIFO; + ints.active=INT_NONE; + ints.requested=0; + + FIFOenabled = false; + FIFOsize = 1; + timeout = 0; + dlab = 0; + ierval = 0; + + initdiv = SERIALBASERATE / bps; + setdivisor(initdiv >> 8, initdiv & 0x0f); + + for (i=8;i<=0xf;i++) { + + IO_RegisterWriteHandler(initbase+i,write_serial,"Serial Port"); + IO_RegisterReadHandler(initbase+i,read_serial,"Serial Port"); + } + + PIC_RegisterIRQ(irq,0,"SERIAL"); + + +}; + +CSerial::~CSerial(void) +{ + +}; + + + +CSerial *getComport(Bitu portnum) +{ + return serialports[portnum-1]; +} + +void SERIAL_Init(Section* sec) { + + unsigned long args = 1; + Section_prop * section=static_cast(sec); + +// if(!section->Get_bool("enabled")) return; + + serialports[0] = new CSerial(0x3f0,4,SERIALBASERATE); + serialports[1] = new CSerial(0x2f0,3,SERIALBASERATE); +} diff --git a/src/hardware/softmodem.cpp b/src/hardware/softmodem.cpp new file mode 100644 index 00000000..dcdf449d --- /dev/null +++ b/src/hardware/softmodem.cpp @@ -0,0 +1,635 @@ +/* + * Copyright (C) 2002 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 Library 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. + */ + +#include +#include "sdl_net.h" + + +#include "dosbox.h" +#include "inout.h" +#include "mixer.h" +#include "dma.h" +#include "pic.h" +#include "hardware.h" +#include "setup.h" +#include "programs.h" +#include "debug.h" +#include "timer.h" +#include "callback.h" +#include "math.h" +#include "regs.h" +#include "serialport.h" + +#define MODEMSPD 57600 +#define CONNECTED (M_CTS | M_DSR | M_DCD ) +#define DISCONNECTED (M_CTS | M_DSR ) + + +/* DTMF tone generator */ +float col[] = { 1209.0, 1336.0, 1477.0, 1633.0 }; +float row[] = { 697.0, 770.0, 852.0, 941.0 }; +char positions[] = "123A456B789C*0#D"; +#define duration 1000 +#define pause 400 + +static Bit8u tmpbuf[FIFO_SIZE+1]; + +struct ModemHd { + char cmdbuf[FIFO_SIZE]; + bool commandmode; + bool cantrans; + bool incomingcall; + bool autoanswer; + bool echo; + Bitu cmdpause; + Bits ringcounter; + Bit16u plusinc; + Bit16u cmdpos; + + + TCPsocket socket; + TCPsocket listensocket; + SDLNet_SocketSet socketset; + + IPaddress openip; + + Bitu comport; + Bitu listenport; + + char remotestr[4096]; + + bool dialing; + float f1, f2; + Bitu diallen; + Bitu dialpos; + char dialstr[256]; + MIXER_Channel * chan; +}; + +static CSerial * mdm; +static ModemHd mhd; + +static void sendStr(const char *usestr) { + if (!mhd.echo) return; + Bitu i=0; + while (*usestr != 0) { + if (*usestr == 10) { + mdm->rx_addb(0xd); + mdm->rx_addb(0xa); + } else { + mdm->rx_addb((Bit8u)*usestr); + } + usestr++; + } +} + +static void sendOK() { + sendStr("\nOK\n"); +} + +static void sendError() { + sendStr("\nERROR\n"); +} + +static void toUpcase(char *buffer) { + Bitu i=0; + while (buffer[i] != 0) { + buffer[i] = toupper(buffer[i]); + i++; + } +} + +static void openConnection() { + if (mhd.socket) { + LOG_MSG("Huh? already connected"); + SDLNet_TCP_DelSocket(mhd.socketset,mhd.socket); + SDLNet_TCP_Close(mhd.socket); + } + mhd.socket = SDLNet_TCP_Open(&mhd.openip); + if (mhd.socket) { + SDLNet_TCP_AddSocket(mhd.socketset,mhd.socket); + sendStr("\nCONNECT 57600\n"); + mhd.commandmode = false; + mdm->setmodemstatus(CONNECTED); + } else { + sendStr("\nNO DIALTONE\n"); + } +} + +static bool Dial(char * host) { + + /* Scan host for port */ + Bit16u port; + char * hasport=strrchr(host,':'); + if (hasport) { + *hasport++=0; + port=(Bit16u)atoi(hasport); + } else port=23; + /* Resolve host we're gonna dial */ + LOG_MSG("host %s port %x",host,port); + if (!SDLNet_ResolveHost(&mhd.openip,host,port)) { + /* Prepare string for dial sound generator */ + int c; + char *addrptr=host; + mhd.dialstr[0] = 'd'; + mhd.dialstr[1] = 'd'; + mhd.dialstr[2] = 'd'; + mhd.dialstr[3] = 'd'; + mhd.dialstr[4] = 'd'; + mhd.dialstr[5] = 'p'; + c=6; + while(*addrptr != 0x00) { + if (strchr(positions, *addrptr)) { + mhd.dialstr[c] = *addrptr; + c++; + } + addrptr++; + } + mhd.dialstr[c] = 0x00; + + mhd.diallen = strlen(mhd.dialstr) * (Bit32u)(duration + pause); + mhd.dialpos = 0; + mhd.f1 = 0; + mhd.f2 = 0; + mhd.dialing = true; + MIXER_Enable(mhd.chan,true); + return true; + } else { + LOG_MSG("Failed to resolve host %s:%s",host,SDLNet_GetError()); + sendStr("\nNO CARRIER\n"); + return false; + } +} + + +static void DoCommand() { + bool found = false; + bool foundat = false; + char *foundstr; + bool connResult = false; + char msgbuf[4096]; + + Bitu result; + mhd.cmdbuf[mhd.cmdpos] = 0; + toUpcase(mhd.cmdbuf); + LOG_MSG("Modem Sent Command: %s\n", mhd.cmdbuf); + mhd.cmdpos = 0; + + result = 0; + + + /* Just for kicks */ + if ((mhd.cmdbuf[0] == 'A') && (mhd.cmdbuf[1] == 'T')) foundat = true; + if (foundat) { + if (strstr(mhd.cmdbuf,"I3")) { + sendStr("\nDosBox Emulated Modem Firmware V1.00\n"); + result = 1; + } + if (strstr(mhd.cmdbuf,"I4")) { + sprintf(msgbuf, "\nModem compiled for DosBox version %s\n", VERSION); + sendStr(msgbuf); + result = 1; + } + if (strstr(mhd.cmdbuf,"S0=1")) { + mhd.autoanswer = true; + } + if (strstr(mhd.cmdbuf,"S0=0")) { + mhd.autoanswer = false; + } + + if (strstr(mhd.cmdbuf,"E0")) { + mhd.echo = false; + } + if (strstr(mhd.cmdbuf,"E1")) { + mhd.echo = true; + } + + if (strstr(mhd.cmdbuf,"ATH")) { + /* Check if we're actually connected */ + if (mhd.socket) { + sendStr("\nNO CARRIER\n"); + SDLNet_TCP_DelSocket(mhd.socketset,mhd.socket); + SDLNet_TCP_Close(mhd.socket); + mhd.socket=0; + mdm->setmodemstatus(DISCONNECTED); + mhd.commandmode = true; + result = 3; + } else result = 2; + } + if(strstr(mhd.cmdbuf,"ATO")) { + /* Check for connection before switching to data mode */ + if (mhd.socket) { + mhd.commandmode = false; + result=3; + } else { + result=2; + } + } + if(strstr(mhd.cmdbuf,"ATDT")) { + foundstr = strstr(mhd.cmdbuf,"ATDT"); + foundstr+=4; + /* Small protection against empty line */ + if (!foundstr[0]) { + result=2; + } else { + connResult = Dial(foundstr); + result=3; + } + } + if(strstr(mhd.cmdbuf,"ATA")) { + if (mhd.incomingcall) { + sendStr("\nCONNECT 57600\n"); + LOG_MSG("Connected!\n"); + MIXER_Enable(mhd.chan,false); + mdm->setmodemstatus(CONNECTED); + mhd.incomingcall = false; + mhd.commandmode = false; + SDLNet_TCP_AddSocket(mhd.socketset,mhd.socket); + result = 3; + } else { + mhd.autoanswer = true; + result = 3; + } + } + if (result==0) result = 1; + } else result=2; + + if (strlen(mhd.cmdbuf)<2) { + if(!mhd.dialing) { + result = 0; + mhd.autoanswer = false; + } else { + MIXER_Enable(mhd.chan,false); + mhd.dialing = false; + sendStr("\nNO CARRIER\n"); + result = 0; + } + } + + switch (result) { + case 1: + sendOK(); + break; + case 2: + sendError(); + break; + } + +} + + +static void MC_Changed(Bitu new_mc) { + + +} + +static void MODEM_Hardware(Bitu ticks) { + int result =0; + unsigned long args = 1; + bool sendbyte = true; + Bitu usesize; + Bit8u txval; + + /* Check for eventual break command */ + if (!mhd.commandmode) mhd.cmdpause++; + /* Handle incoming data from serial port, read as much as available */ + Bitu tx_size=mdm->tx_size(); + while (tx_size--) { + txval = mdm->tx_readb(); + if (mhd.commandmode) { + if(txval != 0xd) { + if(txval == 0x8) { + if (mhd.cmdpos > 0) { + --mhd.cmdpos; + } + } else { + if (txval != '+') { + if(mhd.cmdposrx_addb(txval); + } else if (mhd.echo) { + mdm->rx_addb(10); + mdm->rx_addb(13); + } + } else { + DoCommand(); + } + } else { + /* 1000 ticks have passed, can check for pause command */ + if (mhd.cmdpause > 1000) { + if(txval == '+') { + mhd.plusinc++; + if(mhd.plusinc>=3) { + mhd.commandmode = true; + sendStr("\nOK\n"); + mhd.plusinc = 0; + } + sendbyte=false; + } else { + mhd.plusinc=0; + } +//If not a special pause command, should go for bigger blocks to send + } + + tmpbuf[0] = txval; + tmpbuf[1] = 0x0; + + if (mhd.socket && sendbyte) { + SDLNet_TCP_Send(mhd.socket, tmpbuf,1); + //TODO error testing + } + } + } + + SDLNet_CheckSockets(mhd.socketset,0); + /* Handle outgoing to the serial port */ + if(!mhd.commandmode && mhd.socket && mdm->rx_free() && SDLNet_SocketReady(mhd.socket)) { + usesize = mdm->rx_free(); + result = SDLNet_TCP_Recv(mhd.socket, tmpbuf, usesize); + if (result>0) { + mdm->rx_adds(tmpbuf,result); + mhd.cmdpause = 0; + } else { + /* Error close the socket and disconnect */ + mdm->setmodemstatus(DISCONNECTED); + mhd.commandmode = true; + sendStr("\nNO CARRIER\n"); + SDLNet_TCP_DelSocket(mhd.socketset,mhd.socket); + SDLNet_TCP_Close(mhd.socket); + mhd.socket=0; + } + } + + /* Check for incoming calls */ + if (!mhd.socket && !mhd.incomingcall && mhd.listensocket) { + mhd.socket = SDLNet_TCP_Accept(mhd.listensocket); + if (mhd.socket) { + mhd.dialpos = 0; + mhd.incomingcall = true; + mhd.diallen = 12000; + mhd.dialpos = 0; +//TODO Set ring in Modemstatus? + sendStr("\nRING\n"); + MIXER_Enable(mhd.chan,true); + mhd.ringcounter = 24000; + } + } + + if (mhd.incomingcall) { + if (mhd.ringcounter <= 0) { + if (mhd.autoanswer) { + mhd.incomingcall = false; + sendStr("\nCONNECT 57600\n"); + MIXER_Enable(mhd.chan,false); + mdm->setmodemstatus(CONNECTED); + mhd.incomingcall = false; + mhd.commandmode = false; + SDLNet_TCP_AddSocket(mhd.socketset,mhd.socket); + return; + } + sendStr("\nRING\n"); + mhd.diallen = 12000; + mhd.dialpos = 0; + + MIXER_Enable(mhd.chan,true); + + mhd.ringcounter = 3000; /* Ring every three seconds for accurate emulation */ + + } + if (mhd.ringcounter > 0) --mhd.ringcounter; + + } + +} + +/* +03F8 -W serial port, transmitter holding register (THR), which contains the + character to be sent. Bit 0 is sent first. + bit 7-0 data bits when DLAB=0 (Divisor Latch Access Bit) +03F8 R- receiver buffer register (RBR), which contains the received + character. Bit 0 is received first + bit 7-0 data bits when DLAB=0 (Divisor Latch Access Bit) +03F8 RW divisor latch low byte (DLL) when DLAB=1 (see #P0876) +03F9 RW divisor latch high byte (DLM) when DLAB=1 (see #P0876) +03F9 RW interrupt enable register (IER) when DLAB=0 (see #P0877) +03FA R- interrupt identification register (see #P0878) + Information about a pending interrupt is stored here. When the ID + register is addressed, thehighest priority interrupt is held, and + no other interrupts are acknowledged until the CPU services that + interrupt. +03FA -W 16650 FIFO Control Register (FCR) (see #P0879) +03FB RW line control register (LCR) (see #P0880) +03FC RW modem control register (see #P0881) +03FD R- line status register (LSR) (see #P0882) +03FE R- modem status register (MSR) (see #P0883) +03FF RW scratch register (SCR) + (not used for serial I/O; available to any application using 16450, + 16550) (not present on original 8250) +*/ + +static void MODEM_CallBack(Bit8u * stream,Bit32u len) { + char *cp; + float ci,ri; + Bit32u innum, splitnum, quad, eighth, sixth, amp; + Bit8u curchar; + Bit32s buflen = (Bit32s)len; + if(mhd.incomingcall) { + + if(mhd.dialpos>=mhd.diallen) { + MIXER_Enable(mhd.chan,false); + return; + } else { + quad = (mhd.diallen/14); + eighth = quad / 2; + sixth = eighth /2; + + while ((buflen>0) && (mhd.dialpos=mhd.diallen) { + while(len-->0) { + *(Bit16s*)(stream) = 0; + stream+=2; + } + MIXER_Enable(mhd.chan,false); + mhd.dialing = false; + openConnection(); + return; + } else { + + while ((buflen>0) && (mhd.dialpos(sec); + + if(!section->Get_bool("enabled")) return; + + if(SDLNet_Init()==-1) { + LOG_MSG("SDLNet_Init failed: %s\n", SDLNet_GetError()); + return; + } + + mhd.cmdpos = 0; + mhd.commandmode = true; + mhd.plusinc = 0; + mhd.cantrans = false; + mhd.incomingcall = false; + mhd.autoanswer = false; + mhd.cmdpause = 0; + mhd.echo = true; + + /* Bind the modem to the correct serial port */ + mhd.comport=section->Get_int("comport"); + strcpy(mhd.remotestr, section->Get_string("remote")); + mdm = getComport(mhd.comport); + mdm->setmodemstatus(DISCONNECTED); + mdm->SetMCHandler(&MC_Changed); + + TIMER_RegisterTickHandler(&MODEM_Hardware); + + /* Initialize the sockets and setup the listening port */ + mhd.socketset = SDLNet_AllocSocketSet(1); + if (!mhd.socketset) { + LOG_MSG("MODEM:Can't open socketset:%s",SDLNet_GetError()); +//TODO Should probably just exit + return; + } + mhd.socket=0; + mhd.listenport=section->Get_int("listenport"); + if (mhd.listenport) { + IPaddress listen_ip; + SDLNet_ResolveHost(&listen_ip, NULL, mhd.listenport); + mhd.listensocket=SDLNet_TCP_Open(&listen_ip); + if (!mhd.listensocket) LOG_MSG("MODEM:Can't open listen port:%s",SDLNet_GetError()); + } else mhd.listensocket=0; + + mhd.chan=MIXER_AddChannel(&MODEM_CallBack,8000,"MODEM"); + MIXER_Enable(mhd.chan,false); + MIXER_SetMode(mhd.chan,MIXER_16MONO); +} + + +