Rev 883 | Details | Compare with Previous | 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 | |||
784 | DimkaM | 22 | open_port = u8(port); |
716 | lvd | 23 | |
24 | char portName[11]; |
||
25 | _snprintf(portName, _countof(portName), "\\\\.\\COM%d", port); |
||
26 | |||
784 | DimkaM | 27 | hPort = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr); |
716 | lvd | 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 | |||
784 | DimkaM | 38 | OvW.hEvent = CreateEvent(nullptr, TRUE, TRUE, nullptr); |
39 | OvR.hEvent = CreateEvent(nullptr, TRUE, TRUE, nullptr); |
||
716 | lvd | 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, ×); |
||
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 | { |
||
784 | DimkaM | 93 | written = ULONG(OvW.InternalHigh); |
716 | lvd | 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 | |||
784 | DimkaM | 105 | int needwrite = int(whead - wtail); |
716 | lvd | 106 | if (needwrite < 0) |
107 | needwrite += BSIZE; |
||
108 | if (needwrite && WrReady) |
||
109 | { |
||
110 | if (whead > wtail) |
||
784 | DimkaM | 111 | memcpy(tempwr, wbuf+wtail, size_t(needwrite)); |
716 | lvd | 112 | else |
113 | { |
||
114 | memcpy(tempwr, wbuf+wtail, BSIZE-wtail); |
||
115 | memcpy(tempwr+BSIZE-wtail, wbuf, whead); |
||
116 | } |
||
117 | |||
784 | DimkaM | 118 | if (WriteFile(hPort, tempwr, DWORD(needwrite), &written, &OvW)) |
716 | lvd | 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 | { |
||
784 | DimkaM | 135 | read = ULONG(OvR.InternalHigh); |
716 | lvd | 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 | |||
784 | DimkaM | 149 | int canread = int(rtail - rhead - 1); |
716 | lvd | 150 | if (canread < 0) |
151 | canread += BSIZE; |
||
152 | if (canread && RdReady) |
||
153 | { |
||
784 | DimkaM | 154 | if (ReadFile(hPort, temprd, DWORD(canread), &read, &OvR) && read) |
716 | lvd | 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; |
||
784 | DimkaM | 170 | if(reg[5] & 0x20) |
171 | { |
||
172 | mask |= 2; reg[6] |= 0x10; |
||
173 | } |
||
716 | lvd | 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 |
||
730 | lvd | 319 | if(conf.mem_model == MM_ATM3)result = 0; |
716 | lvd | 320 | if (rhead != rtail) |
321 | { |
||
322 | result = reg[0] = rcbuf[rtail++]; |
||
323 | rtail &= (BSIZE-1); |
||
324 | } |
||
325 | |||
326 | if (rhead != rtail) |
||
327 | reg[5] |= 1; |
||
328 | else |
||
329 | reg[5] &= ~1; |
||
330 | |||
331 | setup_int(); |
||
332 | } |
||
333 | |||
334 | if (nreg == 5) |
||
335 | { |
||
336 | reg[5] &= ~0x0E; |
||
337 | setup_int(); |
||
338 | } |
||
339 | |||
340 | if (nreg == 6) |
||
341 | { |
||
342 | DWORD ModemStatus; |
||
343 | GetCommModemStatus(hPort, &ModemStatus); |
||
344 | u8 r6 = reg[6]; |
||
345 | reg[6] &= ~(1 << 4); |
||
346 | reg[6] |= (ModemStatus & MS_CTS_ON) ? (1 << 4): 0; |
||
347 | reg[6] &= ~1; |
||
348 | reg[6] |= ((r6 ^ reg[6]) & (1 << 4)) >> 4; |
||
349 | result = reg[6]; |
||
350 | } |
||
351 | return result; |
||
352 | } |