1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * Not a parser, but parallel and serial emulation for Win32
5 *
6 * Copyright 1997 Mathias Ortmann
7 * Copyright 1998-1999 Brian King - added MIDI output support
8 */
9
10 #include "sysconfig.h"
11 #include <windows.h>
12 #include <winspool.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <mmsystem.h>
16 #include <ddraw.h>
17 #include <commctrl.h>
18 #include <commdlg.h>
19 #include <stdio.h>
20 #include <fcntl.h>
21 #include <sys/stat.h>
22 #include <io.h>
23
24 #include "sysdeps.h"
25 #include "options.h"
26 #include "gensound.h"
27 #include "events.h"
28 #include "uae.h"
29 #include "memory.h"
30 #include "custom.h"
31 #include "osdep/win32gui.h"
32 #include "osdep/parser.h"
33 #include "osdep/midi.h"
34
35 UINT prttimer;
36 char prtbuf[PRTBUFSIZE];
37 int prtbufbytes,wantwrite;
38 HANDLE hPrt = INVALID_HANDLE_VALUE;
39 DWORD dwJob;
40 extern HWND hAmigaWnd;
41 OVERLAPPED ol = { 0 };
42
flushprtbuf(void)43 void flushprtbuf (void)
44 {
45 DWORD written = 0;
46
47 if (hPrt != INVALID_HANDLE_VALUE)
48 {
49 if( WritePrinter( hPrt, prtbuf, prtbufbytes, &written ) )
50 {
51 if( written != prtbufbytes )
52 write_log ( "PRINTER: Only wrote %d of %d bytes!\n", written, prtbufbytes );
53 }
54 else
55 {
56 write_log ( "PRINTER: Couldn't write data!\n" );
57 }
58 }
59 else
60 {
61 write_log ( "PRINTER: Not open!\n" );
62 }
63 prtbufbytes = 0;
64 }
65
finishjob(void)66 void finishjob (void)
67 {
68 flushprtbuf ();
69 }
70
DoSomeWeirdPrintingStuff(char val)71 void DoSomeWeirdPrintingStuff( char val )
72 {
73 if (prttimer)
74 KillTimer (hAmigaWnd, prttimer);
75 if (prtbufbytes < PRTBUFSIZE) {
76 prtbuf[prtbufbytes++] = val;
77 prttimer = SetTimer (hAmigaWnd, 1, 2000, NULL);
78 } else {
79 flushprtbuf ();
80 *prtbuf = val;
81 prtbufbytes = 1;
82 prttimer = 0;
83 }
84 }
85
openprinter(void)86 FILE *openprinter( void )
87 {
88 FILE *result = NULL;
89 DOC_INFO_1 DocInfo;
90
91 if( ( hPrt == INVALID_HANDLE_VALUE ) && *currprefs.prtname )
92 {
93 if( OpenPrinter(currprefs.prtname, &hPrt, NULL ) )
94 {
95 // Fill in the structure with info about this "document."
96 DocInfo.pDocName = "My Document";
97 DocInfo.pOutputFile = NULL;
98 DocInfo.pDatatype = "RAW";
99 // Inform the spooler the document is beginning.
100 if( (dwJob = StartDocPrinter( hPrt, 1, (LPSTR)&DocInfo )) == 0 )
101 {
102 ClosePrinter( hPrt );
103 hPrt = INVALID_HANDLE_VALUE;
104 }
105 else if( StartPagePrinter( hPrt ) )
106 {
107 result = 1;
108 }
109 }
110 else
111 {
112 hPrt = INVALID_HANDLE_VALUE; // Stupid bug in Win32, where OpenPrinter fails, but hPrt ends up being zero
113 }
114 }
115 if( hPrt != INVALID_HANDLE_VALUE )
116 {
117 write_log ( "PRINTER: Opening printer \"%s\" with handle 0x%x.\n", currprefs.prtname, hPrt );
118 }
119 else if( *currprefs.prtname )
120 {
121 write_log ( "PRINTER: ERROR - Couldn't open printer \"%s\" for output.\n", currprefs.prtname );
122 }
123
124 return result;
125 }
126
closeprinter(void)127 void closeprinter( void )
128 {
129 if( hPrt != INVALID_HANDLE_VALUE )
130 {
131 EndPagePrinter( hPrt );
132 EndDocPrinter( hPrt );
133 ClosePrinter( hPrt );
134 hPrt = INVALID_HANDLE_VALUE;
135 write_log ( "PRINTER: Closing printer.\n" );
136 }
137 KillTimer( hAmigaWnd, prttimer );
138 prttimer = 0;
139 }
140
putprinter(char val)141 void putprinter (char val)
142 {
143 DoSomeWeirdPrintingStuff( val );
144 }
145
146 static HANDLE hCom = INVALID_HANDLE_VALUE;
147 static HANDLE writeevent = NULL;
148 static DCB dcb;
149
150 char inbuf[1024], outbuf[1024];
151 int inptr, inlast, outlast;
152
openser(char * sername)153 int openser (char *sername)
154 {
155 char buf[32];
156 COMMTIMEOUTS CommTimeOuts;
157
158 sprintf (buf, "\\.\\\\%s", sername);
159
160 if (!(writeevent = CreateEvent (NULL, TRUE, FALSE, NULL))) {
161 write_log ("SERIAL: Failed to create event!\n");
162 return 0;
163 }
164 if ((hCom = CreateFile (buf, GENERIC_READ | GENERIC_WRITE,
165 0,
166 NULL,
167 OPEN_EXISTING,
168 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
169 NULL)) != INVALID_HANDLE_VALUE) {
170 SetCommMask (hCom, EV_RXFLAG);
171 SetupComm (hCom, 65536,128);
172 PurgeComm (hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
173 CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
174 CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
175 CommTimeOuts.ReadTotalTimeoutConstant = 0;
176 CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
177 CommTimeOuts.WriteTotalTimeoutConstant = 0;
178 SetCommTimeouts (hCom, &CommTimeOuts);
179
180 GetCommState (hCom, &dcb);
181
182 dcb.BaudRate = 9600;
183 //dcb.ByteSize = 8;
184 //dcb.Parity = 0;
185 //dcb.StopBits = NOPARITY;
186
187 //dcb.fOutxCtsFlow = TRUE;
188 //dcb.fOutxDsrFlow = FALSE;
189 //dcb.fDtrControl = DTR_CONTROL_ENABLE;
190 //dcb.fTXContinueOnXoff = FALSE;
191 //dcb.fOutX = FALSE;
192 //dcb.fInX = FALSE;
193 //dcb.fNull = FALSE;
194 //dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
195 //dcb.fAbortOnError = FALSE;
196
197 if (SetCommState (hCom, &dcb)) {
198 write_log ("SERIAL: Using %s\n", sername);
199 return 1;
200 }
201 CloseHandle (hCom);
202 hCom = INVALID_HANDLE_VALUE;
203 }
204 return 0;
205 }
206
closeser(void)207 void closeser (void)
208 {
209 if (hCom != INVALID_HANDLE_VALUE)
210 {
211 CloseHandle (hCom);
212 hCom = INVALID_HANDLE_VALUE;
213 }
214 if( writeevent )
215 CloseHandle( writeevent );
216 }
217
doserout(void)218 void doserout( void )
219 {
220 DWORD dwErrorFlags;
221 unsigned long actual;
222
223 if (hCom != INVALID_HANDLE_VALUE)
224 {
225 if (outlast)
226 {
227 ResetEvent (ol.hEvent = writeevent);
228 actual = 0;
229
230 if (!WriteFile (hCom, outbuf, outlast, &actual, &ol))
231 {
232 //GetOverlappedResult (hCom, &ol, &actual, FALSE);
233
234 /* while (outlast -= actual)
235 {
236 if ((dwErrorFlags = GetLastError ()) == ERROR_IO_INCOMPLETE || dwErrorFlags == ERROR_IO_PENDING)
237 {
238 actual = 0;
239 GetOverlappedResult (hCom, &ol, &actual, FALSE);
240
241 if ((dwErrorFlags = GetLastError ()) != ERROR_IO_INCOMPLETE && dwErrorFlags != ERROR_IO_PENDING)
242 {
243 write_log ("writeser: error %d, lost %d chars!\n", GetLastError (), outlast - actual);
244 outlast = 0;
245 break;
246 }
247 if (WaitForSingleObject (writeevent, 100) == WAIT_TIMEOUT)
248 {
249 write_log ("writeser: timeout, lost %d chars!\n", outlast - actual);
250 outlast = 0;
251 break;
252 }
253 }
254 else
255 {
256 if (dwErrorFlags)
257 {
258 write_log ("writeser: error %d while writing, lost %d chars!\n", dwErrorFlags, outlast - actual);
259 ClearCommError (hCom, &dwErrorFlags, NULL);
260 }
261
262 outlast = 0;
263 break;
264 }
265
266 }
267 */
268 outlast=0;
269 }
270 }
271 }
272 else
273 {
274 outlast = 0;
275 inptr = inlast = 0;
276 }
277 }
278
writeser(char c)279 void writeser (char c)
280 {
281 COMSTAT ComStat;
282 DWORD dwErrorFlags;
283 extern uae_u16 serdat;
284 {
285 outbuf[ outlast++ ] = c;
286 //serial
287 if (outlast == 100/*sizeof outbuf*/)
288 {
289 doserout();
290 wantwrite=2000;
291 return;
292 }
293 }
294 serdat|=0x2000; /* Set TBE in the SERDATR ... */
295 intreq|=1; /* ... and in INTREQ register */
296 INTREQ( 0x8000 | 0x01 );
297 }
298 int state,oldstatelw,oldstaterw;
299
hsyncstuff(void)300 void hsyncstuff( void ) //only generate Interrupts when
301 //writebuffer is complete flushed
302 //check state of lwin rwin
303
304 {
305 static int keycheck=0;
306 extern uae_u16 serdat;
307 extern int serdev;
308
309 keycheck++;
310 if(keycheck==1000)
311 {
312 state=GetAsyncKeyState(VK_LWIN);
313
314 if (state!=oldstatelw){my_kbd_handler(VK_LWIN,0,state);
315 oldstatelw=state;
316 }
317 state=GetAsyncKeyState(VK_RWIN);
318
319 if (state!=oldstaterw){my_kbd_handler(VK_RWIN,0,state);
320 oldstaterw=state;
321 }
322 keycheck=0;
323 }
324
325 if (!serdev) /* || (serdat&0x4000)) */
326 return;
327
328 if(wantwrite)
329 {
330 int actual=0;
331 if(wantwrite==1)
332 {
333 serdat|=0x2000;
334 intreq|=0x1;
335 INTREQ(0x8000 | (0x01));
336 wantwrite=0;
337 }
338 wantwrite--;
339 GetOverlappedResult (hCom, &ol, &actual, FALSE);
340 if (actual==100)
341 { serdat|=0x2000;
342 intreq|=0x1;
343 INTREQ(0x8000 | (0x01));
344 wantwrite=0;
345 }
346 }
347 }
348
readser(char * buffer)349 int readser (char *buffer)
350 {
351 COMSTAT ComStat;
352 DWORD dwErrorFlags;
353 DWORD result;
354 unsigned long actual;
355
356
357 {
358
359
360 //
361 //if(intreq&&1);
362 //else
363 /*if (WaitForSingleObject (writeevent,0) != WAIT_TIMEOUT)
364 {
365 serdat|=0x2000;
366 intreq|=0x1;
367 INTREQ(0x8000 | (0x01));
368 ResetEvent (ol.hEvent = writeevent);
369
370 }
371 else {INTREQ(0x1);
372 serdat &=0xdfff;
373 }*/
374 if (inptr < inlast)
375 {
376 *buffer = inbuf[inptr++];
377 return 1;
378 }
379 if (hCom != INVALID_HANDLE_VALUE)
380 {
381 inptr = inlast = 0;
382
383 /* only try to read number of bytes in queue */
384 ClearCommError (hCom, &dwErrorFlags, &ComStat);
385 if (ComStat.cbInQue)
386 {
387
388 if (!ReadFile (hCom, inbuf, min (ComStat.cbInQue, sizeof inbuf), &inlast, &ol))
389 {
390 if (GetLastError () == ERROR_IO_PENDING)
391 {
392 write_log ("readser: INTERNAL ERROR - intermittent loss of serial data!\n");
393 for (;;)
394 {
395 actual = 0;
396 result = GetOverlappedResult (hCom, &ol, &actual, TRUE);
397 inlast += actual;
398
399 if (result)
400 break;
401
402 if (GetLastError () != ERROR_IO_INCOMPLETE)
403 {
404 ClearCommError (hCom, &dwErrorFlags, &ComStat);
405 break;
406 }
407 }
408 }
409 else
410 {
411 ClearCommError (hCom, &dwErrorFlags, &ComStat);
412 }
413 }
414 }
415 if (inptr < inlast)
416 {
417 *buffer = inbuf[inptr++];
418 return 1;
419 }
420 }
421 }
422 return 0;
423 }
424
getserstat(int * status)425 void getserstat (int *status)
426 {
427 DWORD stat;
428
429 *status = 0;
430 if (hCom != INVALID_HANDLE_VALUE) {
431 //GetCommModemStatus (hCom, &stat);
432 /* @@@ This "ouch" section was #ifdef 0 before - BDK */
433 #if 0
434 #define TIOCM_CAR 1
435 #define TIOCM_DSR 2
436 /* ouch */
437 if (stat & MS_CTS_ON)
438 *status |= TIOCM_CAR;
439 if (stat & MS_RLSD_ON)
440 *status |= TIOCM_CAR;
441 if (stat & MS_DSR_ON)
442 *status |= TIOCM_DSR;
443 #endif
444 }
445 }
446
setbaud(long baud)447 int setbaud (long baud)
448 {
449 write_log ( "Baud-rate is %d\n", baud );
450 {
451 if (hCom != INVALID_HANDLE_VALUE)
452 {
453 if (GetCommState (hCom, &dcb))
454 {
455 dcb.BaudRate = baud;
456 if (!SetCommState (hCom, &dcb))
457 write_log ("SERIAL: Error setting baud rate %d!\n", baud);
458 }
459 else
460 {
461 write_log ("SERIAL: setbaud internal error!\n");
462 }
463 }
464 }
465 return 0;
466 }
467
468