Subversion Repositories pentevo

Rev

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

  1. #include "std.h"
  2.  
  3. #include "emul.h"
  4. #include "vars.h"
  5.  
  6. #include "util.h"
  7.  
  8. void ISA_MODEM::open(int port)
  9. {
  10.    if (open_port == port)
  11.        return;
  12.    whead = wtail = rhead = rtail = 0;
  13.    if (hPort && hPort != INVALID_HANDLE_VALUE)
  14.    {
  15.        CloseHandle(hPort);
  16.        CloseHandle(OvW.hEvent);
  17.        CloseHandle(OvR.hEvent);
  18.    }
  19.    if (port < 1 || port > 255)
  20.        return;
  21.  
  22.    open_port = u8(port);
  23.  
  24.    char portName[11];
  25.    _snprintf(portName, _countof(portName), "\\\\.\\COM%d", port);
  26.  
  27.    hPort = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
  28.    if (hPort == INVALID_HANDLE_VALUE)
  29.    {
  30.       errmsg("can't open modem on %s", portName); err_win32();
  31.       conf.modem_port = open_port = 0;
  32.       return;
  33.    }
  34.  
  35.    memset(&OvW, 0, sizeof(OvW));
  36.    memset(&OvR, 0, sizeof(OvR));
  37.  
  38.    OvW.hEvent = CreateEvent(nullptr, TRUE, TRUE, nullptr);
  39.    OvR.hEvent = CreateEvent(nullptr, TRUE, TRUE, nullptr);
  40.  
  41.    COMMTIMEOUTS times;
  42.    times.ReadIntervalTimeout = MAXDWORD;
  43.    times.ReadTotalTimeoutMultiplier = 0;
  44.    times.ReadTotalTimeoutConstant = 0;
  45.    times.WriteTotalTimeoutMultiplier = 0;
  46.    times.WriteTotalTimeoutConstant = 0;
  47.    SetCommTimeouts(hPort, &times);
  48.  
  49. #if 0
  50.    DCB dcb;
  51.    if (GetCommState(hPort, &dcb)) {
  52.       printf(
  53.        "modem state:\n"
  54.        "rate=%d\n"
  55.        "parity=%d, OutxCtsFlow=%d, OutxDsrFlow=%d, DtrControl=%d, DsrSensitivity=%d\n"
  56.        "TXContinueOnXoff=%d, OutX=%d, InX=%d, ErrorChar=%d\n"
  57.        "Null=%d, RtsControl=%d, AbortOnError=%d, XonLim=%d, XoffLim=%d\n"
  58.        "ByteSize=%d, Parity=%d, StopBits=%d\n"
  59.        "XonChar=#%02X, XoffChar=#%02X, ErrorChar=#%02X, EofChar=#%02X, EvtChar=#%02X\n\n",
  60.        dcb.BaudRate,
  61.        dcb.fParity, dcb.fOutxCtsFlow, dcb.fOutxDsrFlow, dcb.fDtrControl, dcb.fDsrSensitivity,
  62.        dcb.fTXContinueOnXoff, dcb.fOutX, dcb.fInX, dcb.fErrorChar,
  63.        dcb.fNull, dcb.fRtsControl, dcb.fAbortOnError, dcb.XonLim, dcb.XoffLim,
  64.        dcb.ByteSize, dcb.Parity, dcb.StopBits,
  65.        (BYTE)dcb.XonChar, (BYTE)dcb.XoffChar, (BYTE)dcb.ErrorChar, (BYTE)dcb.EofChar, (BYTE)dcb.EvtChar);
  66.    }
  67. #endif
  68. }
  69.  
  70. void ISA_MODEM::close()
  71. {
  72.    if (!hPort || hPort == INVALID_HANDLE_VALUE)
  73.        return;
  74.    CloseHandle(hPort);
  75.    hPort = INVALID_HANDLE_VALUE;
  76.    open_port = 0;
  77.    CloseHandle(OvW.hEvent);
  78.    CloseHandle(OvR.hEvent);
  79. }
  80.  
  81. void ISA_MODEM::io()
  82. {
  83.    if (!hPort || hPort == INVALID_HANDLE_VALUE)
  84.        return;
  85.  
  86.    static u8 tempwr[BSIZE];
  87.    static u8 temprd[BSIZE];
  88.  
  89.    DWORD written = 0;
  90.    bool WrReady = false;
  91.    if(WaitForSingleObject(OvW.hEvent, 0) == WAIT_OBJECT_0)
  92.    {
  93.        written = ULONG(OvW.InternalHigh);
  94.        OvW.InternalHigh = 0;
  95.        wtail = (wtail+written) & (BSIZE-1);
  96. /*
  97.        if(written)
  98.        {
  99.            printf("write complete: %d\n", written);
  100.        }
  101. */
  102.        WrReady = true;
  103.    }
  104.  
  105.    int needwrite = int(whead - wtail);
  106.    if (needwrite < 0)
  107.        needwrite += BSIZE;
  108.    if (needwrite && WrReady)
  109.    {
  110.       if (whead > wtail)
  111.           memcpy(tempwr, wbuf+wtail, size_t(needwrite));
  112.       else
  113.       {
  114.           memcpy(tempwr, wbuf+wtail, BSIZE-wtail);
  115.           memcpy(tempwr+BSIZE-wtail, wbuf, whead);
  116.       }
  117.  
  118.       if (WriteFile(hPort, tempwr, DWORD(needwrite), &written, &OvW))
  119.       {
  120.       // printf("\nsend: "); dump1(temp, written);
  121.       // printf("writen : %d, %d\n", needwrite, written);
  122.       }
  123.       else
  124.       {
  125.       // printf("write pending : %d, %d\n", needwrite, written);
  126.       }
  127.    }
  128.    if (((whead+1) & (BSIZE-1)) != wtail)
  129.        reg[5] |= 0x60;
  130.  
  131.    bool RdReady = false;
  132.    DWORD read = 0;
  133.    if(WaitForSingleObject(OvR.hEvent, 0) == WAIT_OBJECT_0)
  134.    {
  135.        read = ULONG(OvR.InternalHigh);
  136.        OvR.InternalHigh = 0;
  137.        if(read)
  138.        {
  139.           for (unsigned i = 0; i < read; i++)
  140.           {
  141.               rcbuf[rhead++] = temprd[i];
  142.               rhead &= (BSIZE-1);
  143.           }
  144.        }
  145.  
  146.        RdReady = true;
  147.    }
  148.  
  149.    int canread = int(rtail - rhead - 1);
  150.    if (canread < 0)
  151.        canread += BSIZE;
  152.    if (canread && RdReady)
  153.    {
  154.       if (ReadFile(hPort, temprd, DWORD(canread), &read, &OvR) && read)
  155.       {
  156. //printf("\nrecv: "); dump1(temp, read);
  157.       }
  158.    }
  159.    if (rhead != rtail)
  160.        reg[5] |= 1;
  161.  
  162.    setup_int();
  163. }
  164.  
  165. void ISA_MODEM::setup_int()
  166. {
  167.    reg[6] &= ~0x10;
  168.  
  169.    unsigned char mask = reg[5] & 1;
  170.    if(reg[5] & 0x20)
  171.    {
  172.        mask |= 2; reg[6] |= 0x10;
  173.    }
  174.    if (reg[5] & 0x1E) mask |= 4;
  175.    // if (mask & reg[1]) cpu.nmi()
  176.  
  177.    if (mask & 4) reg[2] = 6;
  178.    else if (mask & 1) reg[2] = 4;
  179.    else if (mask & 2) reg[2] = 2;
  180.    else if (mask & 8) reg[2] = 0;
  181.    else reg[2] = 1;
  182. }
  183.  
  184. void ISA_MODEM::write(unsigned nreg, unsigned char value)
  185. {
  186.    DCB dcb;
  187.  
  188.    if ((1<<nreg) & ((1<<2)|(1<<5)|(1<<6)))
  189.        return; // R/O registers
  190.  
  191.    if (nreg < 2 && (reg[3] & 0x80))
  192.    {
  193.      div[nreg] = value;
  194.      if (GetCommState(hPort, &dcb))
  195.      {
  196.        if (!divfq)
  197.            divfq = 1;
  198.        dcb.BaudRate = 115200 / divfq;
  199.        SetCommState(hPort, &dcb);
  200.      }
  201.      return;
  202.    }
  203.  
  204.    if (nreg == 0)
  205.    { // THR, write char to output buffer
  206.       reg[5] &= ~0x60;
  207.       if (((whead+1) & (BSIZE-1)) == wtail)
  208.       {
  209. /*
  210.          printf("write to ful FIFO\n");
  211.          reg[5] |= 2; // Overrun error  (╬°шсър, ¤ЄюЄ сшЄ Єюы№ъю эр яЁшхь, р эх эр яхЁхфрўє)
  212. */
  213.       }
  214.       else
  215.       {
  216.          wbuf[whead++] = value;
  217.          whead &= (BSIZE-1);
  218.          if (((whead+1) & (BSIZE-1)) != wtail)
  219.              reg[5] |= 0x60; // Transmitter holding register empty | transmitter empty
  220.       }
  221.       setup_int();
  222.       return;
  223.    }
  224.  
  225.    u8 old = reg[nreg];
  226.    reg[nreg] = value;
  227.  
  228.    if(nreg == 2) // FCR
  229.    {
  230.        ULONG Flags = 0;
  231.        if(value & 2) // RX FIFO reset
  232.            Flags |= PURGE_RXCLEAR | PURGE_RXABORT;
  233.  
  234.        if(value & 4) // TX FIFO reset
  235.            Flags |= PURGE_TXCLEAR | PURGE_TXABORT;
  236.  
  237.        if(Flags)
  238.            PurgeComm(hPort, Flags);
  239.    }
  240.  
  241.    // Thu 28 Jul 2005. transfer mode control (code by Alex/AT)
  242.  
  243.    if (nreg == 3)
  244.    {
  245.       // LCR set, renew modem config
  246.       if (!GetCommState(hPort, &dcb))
  247.           return;
  248.  
  249.       dcb.fBinary = TRUE;
  250.       dcb.fParity = (reg[3] & 8)? TRUE : FALSE;
  251.       dcb.fOutxCtsFlow = FALSE;
  252.       dcb.fOutxDsrFlow = FALSE;
  253.       dcb.fDtrControl = DTR_CONTROL_DISABLE;
  254.       dcb.fDsrSensitivity = FALSE;
  255.       dcb.fTXContinueOnXoff = FALSE;
  256.       dcb.fOutX = FALSE;
  257.       dcb.fInX = FALSE;
  258.       dcb.fErrorChar = FALSE;
  259.       dcb.fNull = FALSE;
  260.       dcb.fRtsControl = RTS_CONTROL_DISABLE;
  261.       dcb.fAbortOnError = FALSE;
  262.       dcb.ByteSize = 5 + (reg[3] & 3); // fix by Deathsoft
  263.  
  264.       static const BYTE parity[] = { ODDPARITY, EVENPARITY, MARKPARITY, SPACEPARITY };
  265.       dcb.Parity = (reg[3] & 8) ? parity[(reg[3]>>4) & 3] : NOPARITY;
  266.  
  267.       if (!(reg[3] & 4)) dcb.StopBits = ONESTOPBIT;
  268.       else dcb.StopBits = ((reg[3] & 3) == 1) ? ONE5STOPBITS : TWOSTOPBITS;
  269.  
  270.       SetCommState(hPort, &dcb);
  271.       return;
  272.    }
  273.  
  274.    if (nreg == 4)
  275.    {
  276.       // MCR set, renew DTR/RTS
  277.       if((old ^ reg[4]) & 0x20) // auto rts/cts toggled
  278.       {
  279.           if (!GetCommState(hPort, &dcb))
  280.               return;
  281.  
  282.           if(reg[4] & 0x20) // auto rts/cts enabled
  283.           {
  284.               dcb.fOutxCtsFlow = TRUE;
  285.               dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
  286.           }
  287.           else // auto rts/cts disabled
  288.           {
  289.               dcb.fOutxCtsFlow = FALSE;
  290.               dcb.fRtsControl = RTS_CONTROL_DISABLE;
  291.           }
  292.           SetCommState(hPort, &dcb);
  293.       }
  294.  
  295.       if(!(reg[4] & 0x20)) // auto rts/cts disabled
  296.       {
  297.           if((old ^ reg[4]) & 1)
  298.           {
  299.               EscapeCommFunction(hPort, (reg[4] & 1) ? SETDTR : CLRDTR);
  300.           }
  301.  
  302.           if((old ^ reg[4]) & 2)
  303.           {
  304.               EscapeCommFunction(hPort, (reg[4] & 2) ? SETRTS : CLRRTS);
  305.           }
  306.       }
  307.    }
  308. }
  309.  
  310. unsigned char ISA_MODEM::read(unsigned nreg)
  311. {
  312.    if (nreg < 2 && (reg[3] & 0x80))
  313.        return div[nreg];
  314.  
  315.    unsigned char result = reg[nreg];
  316.  
  317.    if (nreg == 0)
  318.    { // read char from buffer
  319.       if (rhead != rtail)
  320.       {
  321.            result = reg[0] = rcbuf[rtail++];
  322.            rtail &= (BSIZE-1);
  323.       }
  324.  
  325.       if (rhead != rtail)
  326.           reg[5] |= 1;
  327.       else
  328.           reg[5] &= ~1;
  329.  
  330.       setup_int();
  331.    }
  332.  
  333.    if (nreg == 5)
  334.    {
  335.        reg[5] &= ~0x0E;
  336.        setup_int();
  337.    }
  338.  
  339.    if (nreg == 6)
  340.    {
  341.        DWORD ModemStatus;
  342.        GetCommModemStatus(hPort, &ModemStatus);
  343.        u8 r6 = reg[6];
  344.        reg[6] &= ~(1 << 4);
  345.        reg[6] |= (ModemStatus & MS_CTS_ON) ? (1 << 4): 0;
  346.        reg[6] &= ~1;
  347.        reg[6] |= ((r6 ^ reg[6]) & (1 << 4)) >> 4;
  348.        result = reg[6];
  349.    }
  350.    return result;
  351. }
  352.