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