Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
716 lvd 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 = port;
23
 
24
   char portName[11];
25
   _snprintf(portName, _countof(portName), "\\\\.\\COM%d", port);
26
 
27
   hPort = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
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(0, TRUE, TRUE, 0);
39
   OvR.hEvent = CreateEvent(0, TRUE, TRUE, 0);
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 = 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 = whead - wtail;
106
   if (needwrite < 0)
107
       needwrite += BSIZE;
108
   if (needwrite && WrReady)
109
   {
110
      if (whead > wtail)
111
          memcpy(tempwr, wbuf+wtail, 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, 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 = 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 = rtail - rhead - 1;
150
   if (canread < 0)
151
       canread += BSIZE;
152
   if (canread && RdReady)
153
   {
154
      if (ReadFile(hPort, temprd, 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) mask |= 2, reg[6] |= 0x10;
171
   if (reg[5] & 0x1E) mask |= 4;
172
   // if (mask & reg[1]) cpu.nmi()
173
 
174
   if (mask & 4) reg[2] = 6;
175
   else if (mask & 1) reg[2] = 4;
176
   else if (mask & 2) reg[2] = 2;
177
   else if (mask & 8) reg[2] = 0;
178
   else reg[2] = 1;
179
}
180
 
181
void ISA_MODEM::write(unsigned nreg, unsigned char value)
182
{
183
   DCB dcb;
184
 
185
   if ((1<<nreg) & ((1<<2)|(1<<5)|(1<<6)))
186
       return; // R/O registers
187
 
188
   if (nreg < 2 && (reg[3] & 0x80))
189
   {
190
     div[nreg] = value;
191
     if (GetCommState(hPort, &dcb))
192
     {
193
       if (!divfq)
194
           divfq = 1;
195
       dcb.BaudRate = 115200 / divfq;
196
       SetCommState(hPort, &dcb);
197
     }
198
     return;
199
   }
200
 
201
   if (nreg == 0)
202
   { // THR, write char to output buffer
203
      reg[5] &= ~0x60;
204
      if (((whead+1) & (BSIZE-1)) == wtail)
205
      {
206
/*
207
         printf("write to ful FIFO\n");
208
         reg[5] |= 2; // Overrun error  (Ошибка, этот бит только на прием, а не на передачу)
209
*/
210
      }
211
      else
212
      {
213
         wbuf[whead++] = value;
214
         whead &= (BSIZE-1);
215
         if (((whead+1) & (BSIZE-1)) != wtail)
216
             reg[5] |= 0x60; // Transmitter holding register empty | transmitter empty
217
      }
218
      setup_int();
219
      return;
220
   }
221
 
222
   u8 old = reg[nreg];
223
   reg[nreg] = value;
224
 
225
   if(nreg == 2) // FCR
226
   {
227
       ULONG Flags = 0;
228
       if(value & 2) // RX FIFO reset
229
           Flags |= PURGE_RXCLEAR | PURGE_RXABORT;
230
 
231
       if(value & 4) // TX FIFO reset
232
           Flags |= PURGE_TXCLEAR | PURGE_TXABORT;
233
 
234
       if(Flags)
235
           PurgeComm(hPort, Flags);
236
   }
237
 
238
   // Thu 28 Jul 2005. transfer mode control (code by Alex/AT)
239
 
240
   if (nreg == 3)
241
   {
242
      // LCR set, renew modem config
243
      if (!GetCommState(hPort, &dcb))
244
          return;
245
 
246
      dcb.fBinary = TRUE;
247
      dcb.fParity = (reg[3] & 8)? TRUE : FALSE;
248
      dcb.fOutxCtsFlow = FALSE;
249
      dcb.fOutxDsrFlow = FALSE;
250
      dcb.fDtrControl = DTR_CONTROL_DISABLE;
251
      dcb.fDsrSensitivity = FALSE;
252
      dcb.fTXContinueOnXoff = FALSE;
253
      dcb.fOutX = FALSE;
254
      dcb.fInX = FALSE;
255
      dcb.fErrorChar = FALSE;
256
      dcb.fNull = FALSE;
257
      dcb.fRtsControl = RTS_CONTROL_DISABLE;
258
      dcb.fAbortOnError = FALSE;
259
      dcb.ByteSize = 5 + (reg[3] & 3); // fix by Deathsoft
260
 
261
      static const BYTE parity[] = { ODDPARITY, EVENPARITY, MARKPARITY, SPACEPARITY };
262
      dcb.Parity = (reg[3] & 8) ? parity[(reg[3]>>4) & 3] : NOPARITY;
263
 
264
      if (!(reg[3] & 4)) dcb.StopBits = ONESTOPBIT;
265
      else dcb.StopBits = ((reg[3] & 3) == 1) ? ONE5STOPBITS : TWOSTOPBITS;
266
 
267
      SetCommState(hPort, &dcb);
268
      return;
269
   }
270
 
271
   if (nreg == 4)
272
   {
273
      // MCR set, renew DTR/RTS
274
      if((old ^ reg[4]) & 0x20) // auto rts/cts toggled
275
      {
276
          if (!GetCommState(hPort, &dcb))
277
              return;
278
 
279
          if(reg[4] & 0x20) // auto rts/cts enabled
280
          {
281
              dcb.fOutxCtsFlow = TRUE;
282
              dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
283
          }
284
          else // auto rts/cts disabled
285
          {
286
              dcb.fOutxCtsFlow = FALSE;
287
              dcb.fRtsControl = RTS_CONTROL_DISABLE;
288
          }
289
          SetCommState(hPort, &dcb);
290
      }
291
 
292
      if(!(reg[4] & 0x20)) // auto rts/cts disabled
293
      {
294
          if((old ^ reg[4]) & 1)
295
          {
296
              EscapeCommFunction(hPort, (reg[4] & 1) ? SETDTR : CLRDTR);
297
          }
298
 
299
          if((old ^ reg[4]) & 2)
300
          {
301
              EscapeCommFunction(hPort, (reg[4] & 2) ? SETRTS : CLRRTS);
302
          }
303
      }
304
   }
305
}
306
 
307
unsigned char ISA_MODEM::read(unsigned nreg)
308
{
309
   if (nreg < 2 && (reg[3] & 0x80))
310
       return div[nreg];
311
 
312
   unsigned char result = reg[nreg];
313
 
314
   if (nreg == 0)
315
   { // read char from buffer
316
      if (rhead != rtail)
317
      {
318
           result = reg[0] = rcbuf[rtail++];
319
           rtail &= (BSIZE-1);
320
      }
321
 
322
      if (rhead != rtail)
323
          reg[5] |= 1;
324
      else
325
          reg[5] &= ~1;
326
 
327
      setup_int();
328
   }
329
 
330
   if (nreg == 5)
331
   {
332
       reg[5] &= ~0x0E;
333
       setup_int();
334
   }
335
 
336
   if (nreg == 6)
337
   {
338
       DWORD ModemStatus;
339
       GetCommModemStatus(hPort, &ModemStatus);
340
       u8 r6 = reg[6];
341
       reg[6] &= ~(1 << 4);
342
       reg[6] |= (ModemStatus & MS_CTS_ON) ? (1 << 4): 0;
343
       reg[6] &= ~1;
344
       reg[6] |= ((r6 ^ reg[6]) & (1 << 4)) >> 4;
345
       result = reg[6];
346
   }
347
   return result;
348
}