Top secrets sources NedoPC pentevo

Rev

Rev 799 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

#include "std.h"

#include "emul.h"
#include "vars.h"

#include "util.h"

void ISA_MODEM::open(int port)
{
   if (open_port == port)
       return;
   whead = wtail = rhead = rtail = 0;
   if (hPort && hPort != INVALID_HANDLE_VALUE)
   {
       CloseHandle(hPort);
       CloseHandle(OvW.hEvent);
       CloseHandle(OvR.hEvent);
   }
   if (port < 1 || port > 255)
       return;

   open_port = u8(port);

   char portName[11];
   _snprintf(portName, _countof(portName), "\\\\.\\COM%d", port);

   hPort = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
   if (hPort == INVALID_HANDLE_VALUE)
   {
      errmsg("can't open modem on %s", portName); err_win32();
      conf.modem_port = open_port = 0;
      return;
   }

   memset(&OvW, 0, sizeof(OvW));
   memset(&OvR, 0, sizeof(OvR));

   OvW.hEvent = CreateEvent(nullptr, TRUE, TRUE, nullptr);
   OvR.hEvent = CreateEvent(nullptr, TRUE, TRUE, nullptr);

   COMMTIMEOUTS times;
   times.ReadIntervalTimeout = MAXDWORD;
   times.ReadTotalTimeoutMultiplier = 0;
   times.ReadTotalTimeoutConstant = 0;
   times.WriteTotalTimeoutMultiplier = 0;
   times.WriteTotalTimeoutConstant = 0;
   SetCommTimeouts(hPort, &times);

#if 0
   DCB dcb;
   if (GetCommState(hPort, &dcb)) {
      printf(
       "modem state:\n"
       "rate=%d\n"
       "parity=%d, OutxCtsFlow=%d, OutxDsrFlow=%d, DtrControl=%d, DsrSensitivity=%d\n"
       "TXContinueOnXoff=%d, OutX=%d, InX=%d, ErrorChar=%d\n"
       "Null=%d, RtsControl=%d, AbortOnError=%d, XonLim=%d, XoffLim=%d\n"
       "ByteSize=%d, Parity=%d, StopBits=%d\n"
       "XonChar=#%02X, XoffChar=#%02X, ErrorChar=#%02X, EofChar=#%02X, EvtChar=#%02X\n\n",
       dcb.BaudRate,
       dcb.fParity, dcb.fOutxCtsFlow, dcb.fOutxDsrFlow, dcb.fDtrControl, dcb.fDsrSensitivity,
       dcb.fTXContinueOnXoff, dcb.fOutX, dcb.fInX, dcb.fErrorChar,
       dcb.fNull, dcb.fRtsControl, dcb.fAbortOnError, dcb.XonLim, dcb.XoffLim,
       dcb.ByteSize, dcb.Parity, dcb.StopBits,
       (BYTE)dcb.XonChar, (BYTE)dcb.XoffChar, (BYTE)dcb.ErrorChar, (BYTE)dcb.EofChar, (BYTE)dcb.EvtChar);
   }
#endif
}

void ISA_MODEM::close()
{
   if (!hPort || hPort == INVALID_HANDLE_VALUE)
       return;
   CloseHandle(hPort);
   hPort = INVALID_HANDLE_VALUE;
   open_port = 0;
   CloseHandle(OvW.hEvent);
   CloseHandle(OvR.hEvent);
}

void ISA_MODEM::io()
{
   if (!hPort || hPort == INVALID_HANDLE_VALUE)
       return;

   static u8 tempwr[BSIZE];
   static u8 temprd[BSIZE];

   DWORD written = 0;
   bool WrReady = false;
   if(WaitForSingleObject(OvW.hEvent, 0) == WAIT_OBJECT_0)
   {
       written = ULONG(OvW.InternalHigh);
       OvW.InternalHigh = 0;
       wtail = (wtail+written) & (BSIZE-1);
/*
       if(written)
       {
           printf("write complete: %d\n", written);
       }
*/

       WrReady = true;
   }

   int needwrite = int(whead - wtail);
   if (needwrite < 0)
       needwrite += BSIZE;
   if (needwrite && WrReady)
   {
      if (whead > wtail)
          memcpy(tempwr, wbuf+wtail, size_t(needwrite));
      else
      {
          memcpy(tempwr, wbuf+wtail, BSIZE-wtail);
          memcpy(tempwr+BSIZE-wtail, wbuf, whead);
      }

      if (WriteFile(hPort, tempwr, DWORD(needwrite), &written, &OvW))
      {
      // printf("\nsend: "); dump1(temp, written);
      // printf("writen : %d, %d\n", needwrite, written);
      }
      else
      {
      // printf("write pending : %d, %d\n", needwrite, written);
      }
   }
   if (((whead+1) & (BSIZE-1)) != wtail)
       reg[5] |= 0x60;

   bool RdReady = false;
   DWORD read = 0;
   if(WaitForSingleObject(OvR.hEvent, 0) == WAIT_OBJECT_0)
   {
       read = ULONG(OvR.InternalHigh);
       OvR.InternalHigh = 0;
       if(read)
       {
          for (unsigned i = 0; i < read; i++)
          {
              rcbuf[rhead++] = temprd[i];
              rhead &= (BSIZE-1);
          }
       }
 
       RdReady = true;
   }

   int canread = int(rtail - rhead - 1);
   if (canread < 0)
       canread += BSIZE;
   if (canread && RdReady)
   {
      if (ReadFile(hPort, temprd, DWORD(canread), &read, &OvR) && read)
      {
//printf("\nrecv: "); dump1(temp, read);
      }
   }
   if (rhead != rtail)
       reg[5] |= 1;

   setup_int();
}

void ISA_MODEM::setup_int()
{
   reg[6] &= ~0x10;

   unsigned char mask = reg[5] & 1;
   if(reg[5] & 0x20)
   {
       mask |= 2; reg[6] |= 0x10;
   }
   if (reg[5] & 0x1E) mask |= 4;
   // if (mask & reg[1]) cpu.nmi()

   if (mask & 4) reg[2] = 6;
   else if (mask & 1) reg[2] = 4;
   else if (mask & 2) reg[2] = 2;
   else if (mask & 8) reg[2] = 0;
   else reg[2] = 1;
}

void ISA_MODEM::write(unsigned nreg, unsigned char value)
{
   DCB dcb;

   if ((1<<nreg) & ((1<<2)|(1<<5)|(1<<6)))
       return; // R/O registers

   if (nreg < 2 && (reg[3] & 0x80))
   {
     div[nreg] = value;
     if (GetCommState(hPort, &dcb))
     {
       if (!divfq)
           divfq = 1;
       dcb.BaudRate = 115200 / divfq;
       SetCommState(hPort, &dcb);
     }
     return;
   }

   if (nreg == 0)
   { // THR, write char to output buffer
      reg[5] &= ~0x60;
      if (((whead+1) & (BSIZE-1)) == wtail)
      {
/*
         printf("write to ful FIFO\n");
         reg[5] |= 2; // Overrun error  (Îøèáêà, ýòîò áèò òîëüêî íà ïðèåì, à íå íà ïåðåäà÷ó)
*/

      }
      else
      {
         wbuf[whead++] = value;
         whead &= (BSIZE-1);
         if (((whead+1) & (BSIZE-1)) != wtail)
             reg[5] |= 0x60; // Transmitter holding register empty | transmitter empty
      }
      setup_int();
      return;
   }

   u8 old = reg[nreg];
   reg[nreg] = value;

   if(nreg == 2) // FCR
   {
       ULONG Flags = 0;
       if(value & 2) // RX FIFO reset
           Flags |= PURGE_RXCLEAR | PURGE_RXABORT;

       if(value & 4) // TX FIFO reset
           Flags |= PURGE_TXCLEAR | PURGE_TXABORT;

       if(Flags)
           PurgeComm(hPort, Flags);
   }

   // Thu 28 Jul 2005. transfer mode control (code by Alex/AT)

   if (nreg == 3)
   {
      // LCR set, renew modem config
      if (!GetCommState(hPort, &dcb))
          return;

      dcb.fBinary = TRUE;
      dcb.fParity = (reg[3] & 8)? TRUE : FALSE;
      dcb.fOutxCtsFlow = FALSE;
      dcb.fOutxDsrFlow = FALSE;
      dcb.fDtrControl = DTR_CONTROL_DISABLE;
      dcb.fDsrSensitivity = FALSE;
      dcb.fTXContinueOnXoff = FALSE;
      dcb.fOutX = FALSE;
      dcb.fInX = FALSE;
      dcb.fErrorChar = FALSE;
      dcb.fNull = FALSE;
      dcb.fRtsControl = RTS_CONTROL_DISABLE;
      dcb.fAbortOnError = FALSE;
      dcb.ByteSize = 5 + (reg[3] & 3); // fix by Deathsoft

      static const BYTE parity[] = { ODDPARITY, EVENPARITY, MARKPARITY, SPACEPARITY };
      dcb.Parity = (reg[3] & 8) ? parity[(reg[3]>>4) & 3] : NOPARITY;

      if (!(reg[3] & 4)) dcb.StopBits = ONESTOPBIT;
      else dcb.StopBits = ((reg[3] & 3) == 1) ? ONE5STOPBITS : TWOSTOPBITS;

      SetCommState(hPort, &dcb);
      return;
   }

   if (nreg == 4)
   {
      // MCR set, renew DTR/RTS
      if((old ^ reg[4]) & 0x20) // auto rts/cts toggled
      {
          if (!GetCommState(hPort, &dcb))
              return;

          if(reg[4] & 0x20) // auto rts/cts enabled
          {
              dcb.fOutxCtsFlow = TRUE;
              dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
          }
          else // auto rts/cts disabled
          {
              dcb.fOutxCtsFlow = FALSE;
              dcb.fRtsControl = RTS_CONTROL_DISABLE;
          }
          SetCommState(hPort, &dcb);
      }

      if(!(reg[4] & 0x20)) // auto rts/cts disabled
      {
          if((old ^ reg[4]) & 1)
          {
              EscapeCommFunction(hPort, (reg[4] & 1) ? SETDTR : CLRDTR);
          }

          if((old ^ reg[4]) & 2)
          {
              EscapeCommFunction(hPort, (reg[4] & 2) ? SETRTS : CLRRTS);
          }
      }
   }
}

unsigned char ISA_MODEM::read(unsigned nreg)
{
   if (nreg < 2 && (reg[3] & 0x80))
       return div[nreg];

   unsigned char result = reg[nreg];

   if (nreg == 0)
   { // read char from buffer
      if(conf.mem_model == MM_ATM3)result = 0;
      if (rhead != rtail)
      {
           result = reg[0] = rcbuf[rtail++];
           rtail &= (BSIZE-1);
      }

      if (rhead != rtail)
          reg[5] |= 1;
      else
          reg[5] &= ~1;

      setup_int();
   }

   if (nreg == 5)
   {
       reg[5] &= ~0x0E;
       setup_int();
   }

   if (nreg == 6)
   {
       DWORD ModemStatus;
       GetCommModemStatus(hPort, &ModemStatus);
       u8 r6 = reg[6];
       reg[6] &= ~(1 << 4);
       reg[6] |= (ModemStatus & MS_CTS_ON) ? (1 << 4): 0;
       reg[6] &= ~1;
       reg[6] |= ((r6 ^ reg[6]) & (1 << 4)) >> 4;
       result = reg[6];
   }
   return result;
}