|
|
1.1 root 1: /*
1.1.1.4 root 2: Hatari - rs232.c
1.1 root 3:
1.1.1.18 root 4: This file is distributed under the GNU General Public License, version 2
5: or at your option any later version. Read the file gpl.txt for details.
1.1 root 6:
1.1.1.4 root 7: RS-232 Communications
1.1.1.3 root 8:
1.1.1.4 root 9: This is similar to the printing functions, we open a direct file
10: (e.g. /dev/ttyS0) and send bytes over it.
11: Using such method mimicks the ST exactly, and even allows us to connect
12: to an actual ST! To wait for incoming data, we create a thread which copies
13: the bytes into an input buffer. This method fits in with the internet code
14: which also reads data into a buffer.
15: */
1.1.1.13 root 16: const char RS232_fileid[] = "Hatari rs232.c : " __DATE__ " " __TIME__;
1.1.1.4 root 17:
1.1.1.9 root 18: #include <config.h>
1.1.1.4 root 19:
20: #if HAVE_TERMIOS_H
21: # include <termios.h>
22: # include <unistd.h>
23: #endif
24:
25: #include <SDL.h>
26: #include <SDL_thread.h>
27: #include <errno.h>
1.1.1.3 root 28:
1.1 root 29: #include "main.h"
1.1.1.4 root 30: #include "configuration.h"
1.1.1.10 root 31: #include "ioMem.h"
1.1.1.8 root 32: #include "m68000.h"
1.1.1.4 root 33: #include "mfp.h"
1.1 root 34: #include "rs232.h"
1.1.1.2 root 35:
1.1 root 36:
1.1.1.4 root 37: #define RS232_DEBUG 0
38:
39: #if RS232_DEBUG
40: #define Dprintf(a) printf a
41: #else
42: #define Dprintf(a)
43: #endif
44:
45:
1.1.1.8 root 46: static FILE *hComIn = NULL; /* Handle to file for reading */
47: static FILE *hComOut = NULL; /* Handle to file for writing */
1.1.1.4 root 48:
1.1.1.20! root 49: #define MAX_RS232INPUT_BUFFER 2048 /* Must be ^2 */
! 50:
1.1.1.8 root 51: static unsigned char InputBuffer_RS232[MAX_RS232INPUT_BUFFER];
52: static int InputBuffer_Head=0, InputBuffer_Tail=0;
1.1.1.19 root 53: static volatile bool bQuitThread = false;
1.1.1.8 root 54:
55: #if HAVE_TERMIOS_H
56:
57: #if !HAVE_CFMAKERAW
1.1.1.4 root 58: static inline void cfmakeraw(struct termios *termios_p)
59: {
60: termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
61: termios_p->c_oflag &= ~OPOST;
62: termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
63: termios_p->c_cflag &= ~(CSIZE|PARENB);
64: termios_p->c_cflag |= CS8;
65: }
66: #endif
67:
1.1.1.9 root 68:
69: #if defined(__AMIGAOS4__)
70:
71: // dummy functions. REMOVE THEM LATER
72:
73: int tcgetattr(int file_descriptor,struct termios *tios_p)
74: {
75: return -1;
76: }
77:
78: int tcsetattr(int file_descriptor,int action,struct termios *tios_p)
79: {
80: return -1;
81: }
82:
83: int cfsetospeed(struct termios *tios, speed_t ospeed)
84: {
85:
86: tios->c_ospeed = ospeed;
87:
88: return 0;
89: }
90:
91:
92: int cfsetispeed(struct termios *tios,speed_t ispeed)
93: {
94: tios->c_ispeed = ispeed;
95:
96: return 0;
97: }
98:
99: #endif /* __AMIGAOS4__ */
100:
101:
1.1.1.4 root 102: /*-----------------------------------------------------------------------*/
1.1.1.9 root 103: /**
104: * Set serial line parameters to "raw" mode.
105: */
1.1.1.11 root 106: static bool RS232_SetRawMode(FILE *fhndl)
1.1 root 107: {
1.1.1.8 root 108: struct termios termmode;
109: int fd;
1.1 root 110:
1.1.1.8 root 111: memset (&termmode, 0, sizeof(termmode)); /* Init with zeroes */
112: fd = fileno(fhndl); /* Get file descriptor */
1.1.1.4 root 113:
1.1.1.8 root 114: if (isatty(fd))
1.1.1.4 root 115: {
1.1.1.8 root 116: if (tcgetattr(fd, &termmode) != 0)
1.1.1.13 root 117: return false;
1.1.1.8 root 118:
119: /* Set "raw" mode: */
120: termmode.c_cc[VMIN] = 1;
121: termmode.c_cc[VTIME] = 0;
122: cfmakeraw(&termmode);
123: if (tcsetattr(fd, TCSADRAIN, &termmode) != 0)
1.1.1.13 root 124: return false;
1.1.1.4 root 125: }
126:
1.1.1.13 root 127: return true;
1.1.1.8 root 128: }
1.1.1.4 root 129:
130: /*-----------------------------------------------------------------------*/
1.1.1.9 root 131: /**
132: * Set hardware configuration of RS-232:
133: * - Bits per character
134: * - Parity
135: * - Start/stop bits
136: */
1.1.1.14 root 137: static bool RS232_SetBitsConfig(FILE *fhndl, int nCharSize, int nStopBits, bool bUseParity, bool bEvenParity)
1.1.1.4 root 138: {
139: struct termios termmode;
1.1.1.14 root 140: int fd;
1.1.1.4 root 141:
142: memset (&termmode, 0, sizeof(termmode)); /* Init with zeroes */
1.1.1.14 root 143: fd = fileno(fhndl);
1.1.1.4 root 144:
145: if (isatty(fd))
146: {
147: if (tcgetattr(fd, &termmode) != 0)
1.1.1.8 root 148: {
149: Dprintf(("RS232_SetBitsConfig: tcgetattr failed.\n"));
1.1.1.13 root 150: return false;
1.1.1.8 root 151: }
1.1.1.4 root 152:
1.1.1.8 root 153: /* Set the character size: */
154: termmode.c_cflag &= ~CSIZE;
155: switch (nCharSize)
156: {
157: case 8: termmode.c_cflag |= CS8; break;
158: case 7: termmode.c_cflag |= CS7; break;
159: case 6: termmode.c_cflag |= CS6; break;
160: case 5: termmode.c_cflag |= CS5; break;
161: }
162:
163: /* Set stop bits: */
164: if (nStopBits >= 2)
165: termmode.c_oflag |= CSTOPB;
166: else
167: termmode.c_oflag &= ~CSTOPB;
168:
169: /* Parity bit: */
170: if (bUseParity)
171: termmode.c_cflag |= PARENB;
172: else
173: termmode.c_cflag &= ~PARENB;
174:
175: if (bEvenParity)
176: termmode.c_cflag &= ~PARODD;
177: else
178: termmode.c_cflag |= PARODD;
179:
180: /* Now store the configuration: */
1.1.1.4 root 181: if (tcsetattr(fd, TCSADRAIN, &termmode) != 0)
1.1.1.8 root 182: {
183: Dprintf(("RS232_SetBitsConfig: tcsetattr failed.\n"));
1.1.1.13 root 184: return false;
1.1.1.8 root 185: }
1.1.1.4 root 186: }
187:
1.1.1.13 root 188: return true;
1.1 root 189: }
1.1.1.8 root 190:
1.1.1.4 root 191: #endif /* HAVE_TERMIOS_H */
1.1 root 192:
1.1.1.4 root 193:
194: /*-----------------------------------------------------------------------*/
1.1.1.9 root 195: /**
196: * Open file on COM port.
197: */
1.1.1.11 root 198: static bool RS232_OpenCOMPort(void)
1.1 root 199: {
1.1.1.17 root 200: bool ok = true;
1.1.1.3 root 201:
1.1.1.17 root 202: if (!hComOut && ConfigureParams.RS232.szOutFileName[0])
1.1.1.4 root 203: {
1.1.1.17 root 204: /* Create our COM file for output */
205: hComOut = fopen(ConfigureParams.RS232.szOutFileName, "wb");
206: if (hComOut)
207: {
208: setvbuf(hComOut, NULL, _IONBF, 0);
1.1.1.4 root 209: #if HAVE_TERMIOS_H
1.1.1.17 root 210: /* First set the output parameters to "raw" mode */
211: if (!RS232_SetRawMode(hComOut))
212: {
213: Log_Printf(LOG_WARN, "Can't set raw mode for %s\n",
214: ConfigureParams.RS232.szOutFileName);
215: }
216: #endif
217: Dprintf(("Successfully opened RS232 output file.\n"));
218: }
219: else
220: {
221: Log_Printf(LOG_WARN, "RS232: Failed to open output file %s\n",
222: ConfigureParams.RS232.szOutFileName);
223: ok = false;
224: }
1.1.1.4 root 225: }
226:
1.1.1.17 root 227: if (!hComIn && ConfigureParams.RS232.szInFileName[0])
1.1.1.4 root 228: {
1.1.1.17 root 229: /* Create our COM file for input */
230: hComIn = fopen(ConfigureParams.RS232.szInFileName, "rb");
231: if (hComIn)
232: {
233: setvbuf(hComIn, NULL, _IONBF, 0);
234: #if HAVE_TERMIOS_H
235: /* Now set the input parameters to "raw" mode */
236: if (!RS232_SetRawMode(hComIn))
237: {
238: Log_Printf(LOG_WARN, "Can't set raw mode for %s\n",
239: ConfigureParams.RS232.szInFileName);
240: }
1.1.1.4 root 241: #endif
1.1.1.17 root 242: Dprintf(("Successfully opened RS232 input file.\n"));
243: }
244: else
245: {
246: Log_Printf(LOG_WARN, "RS232: Failed to open input file %s\n",
247: ConfigureParams.RS232.szInFileName);
248: ok = false;
249: }
250: }
251: return ok;
1.1 root 252: }
253:
1.1.1.4 root 254:
255: /*-----------------------------------------------------------------------*/
1.1.1.9 root 256: /**
257: * Close file on COM port
258: */
1.1.1.8 root 259: static void RS232_CloseCOMPort(void)
1.1 root 260: {
1.1.1.17 root 261: if (hComIn)
1.1.1.4 root 262: {
263: /* Close */
264: fclose(hComIn);
265: hComIn = NULL;
1.1.1.17 root 266: }
267: if (hComOut)
268: {
1.1.1.4 root 269: fclose(hComOut);
270: hComOut = NULL;
271: }
1.1.1.17 root 272: Dprintf(("Closed RS232 files.\n"));
1.1 root 273: }
274:
1.1.1.4 root 275:
1.1.1.8 root 276: /* thread stuff */
277: static SDL_sem* pSemFreeBuf; /* Semaphore to sync free space in InputBuffer_RS232 */
278: static SDL_Thread *RS232Thread = NULL; /* Thread handle for reading incoming data */
279:
280:
1.1.1.4 root 281: /*-----------------------------------------------------------------------*/
1.1.1.9 root 282: /**
283: * Add incoming bytes from other machine into our input buffer
284: */
1.1.1.8 root 285: static void RS232_AddBytesToInputBuffer(unsigned char *pBytes, int nBytes)
1.1.1.4 root 286: {
1.1.1.8 root 287: int i;
1.1 root 288:
1.1.1.8 root 289: /* Copy bytes into input buffer */
290: for (i=0; i<nBytes; i++)
291: {
292: SDL_SemWait(pSemFreeBuf); /* Wait for free space in buffer */
293: InputBuffer_RS232[InputBuffer_Tail] = *pBytes++;
294: InputBuffer_Tail = (InputBuffer_Tail+1) % MAX_RS232INPUT_BUFFER;
295: }
296: }
1.1.1.4 root 297:
1.1.1.8 root 298:
299: /*-----------------------------------------------------------------------*/
1.1.1.9 root 300: /**
301: * Thread to read incoming RS-232 data, and pass to emulator input buffer
302: */
1.1.1.8 root 303: static int RS232_ThreadFunc(void *pData)
304: {
305: int iInChar;
306: unsigned char cInChar;
307:
308: /* Check for any RS-232 incoming data */
1.1.1.19 root 309: while (!bQuitThread)
1.1.1.4 root 310: {
1.1.1.8 root 311: if (hComIn)
1.1.1.4 root 312: {
1.1.1.8 root 313: /* Read the bytes in, if we have any */
314: iInChar = fgetc(hComIn);
315: if (iInChar != EOF)
316: {
317: /* Copy into our internal queue */
318: cInChar = iInChar;
319: RS232_AddBytesToInputBuffer(&cInChar, 1);
320: /* FIXME: Use semaphores to lock MFP variables? */
1.1.1.18 root 321: MFP_InputOnChannel ( MFP_INT_RCV_BUF_FULL , 0 );
1.1.1.8 root 322: Dprintf(("RS232: Read character $%x\n", iInChar));
1.1.1.15 root 323: /* Sleep for a while */
324: SDL_Delay(2);
1.1.1.8 root 325: }
326: else
327: {
328: /*Dprintf(("RS232: Reached end of input file!\n"));*/
1.1.1.15 root 329: /* potential data race on hComIn modification */
1.1.1.8 root 330: clearerr(hComIn);
331: SDL_Delay(20);
332: }
333: }
334: else
1.1.1.4 root 335: {
1.1.1.15 root 336: /* No RS-232 connection, sleep for 0.2s */
337: SDL_Delay(200);
1.1.1.4 root 338: }
1.1.1.8 root 339: }
1.1.1.4 root 340:
1.1.1.13 root 341: return true;
1.1.1.8 root 342: }
1.1.1.4 root 343:
344:
1.1.1.8 root 345: /*-----------------------------------------------------------------------*/
1.1.1.9 root 346: /**
347: * Initialize RS-232, start thread to wait for incoming data
1.1.1.15 root 348: * (we will open a connection when first bytes are sent even
349: * if RS-232 isn't initialized for reading).
1.1.1.9 root 350: */
1.1.1.8 root 351: void RS232_Init(void)
352: {
353: if (ConfigureParams.RS232.bEnableRS232)
354: {
1.1.1.17 root 355: if (!RS232_OpenCOMPort())
356: {
357: RS232_CloseCOMPort();
358: Log_AlertDlg(LOG_ERROR, "RS232 input or output file open failed. RS232 support disabled.");
359: ConfigureParams.RS232.bEnableRS232 = false;
360: return;
361: }
362: }
363: if (hComIn)
364: {
1.1.1.8 root 365: /* Create semaphore */
366: if (pSemFreeBuf == NULL)
367: pSemFreeBuf = SDL_CreateSemaphore(MAX_RS232INPUT_BUFFER);
368: if (pSemFreeBuf == NULL)
369: {
1.1.1.17 root 370: RS232_CloseCOMPort();
1.1.1.14 root 371: Log_Printf(LOG_WARN, "RS232_Init: Can't create semaphore!\n");
1.1.1.8 root 372: return;
373: }
1.1.1.4 root 374:
1.1.1.8 root 375: /* Create thread to wait for incoming bytes over RS-232 */
376: if (!RS232Thread)
1.1.1.4 root 377: {
1.1.1.19 root 378: bQuitThread = false;
379: #if WITH_SDL2
380: RS232Thread = SDL_CreateThread(RS232_ThreadFunc, "rs232", NULL);
381: #else
1.1.1.8 root 382: RS232Thread = SDL_CreateThread(RS232_ThreadFunc, NULL);
1.1.1.19 root 383: #endif
1.1.1.8 root 384: Dprintf(("RS232 thread has been created.\n"));
1.1.1.4 root 385: }
386: }
1.1.1.8 root 387: }
1.1.1.4 root 388:
1.1.1.8 root 389:
390: /*-----------------------------------------------------------------------*/
1.1.1.9 root 391: /**
392: * Close RS-232 connection and stop checking for incoming data.
393: */
1.1.1.8 root 394: void RS232_UnInit(void)
395: {
396: /* Close, kill thread and free resource */
397: if (RS232Thread)
398: {
1.1.1.15 root 399: /* Instead of killing the thread directly, we should
400: * probably better inform it via IPC so that it can
401: * terminate gracefully... but then we would need to
402: * wait until it exits, otherwise there's a data race
403: * on accessing/modifying hComIn.
404: */
1.1.1.8 root 405: Dprintf(("Killing RS232 thread...\n"));
1.1.1.19 root 406: bQuitThread = true;
407: #if !WITH_SDL2
1.1.1.8 root 408: SDL_KillThread(RS232Thread);
1.1.1.19 root 409: #endif
1.1.1.8 root 410: RS232Thread = NULL;
411: }
412: RS232_CloseCOMPort();
1.1.1.9 root 413:
1.1.1.8 root 414: if (pSemFreeBuf)
415: {
416: SDL_DestroySemaphore(pSemFreeBuf);
417: pSemFreeBuf = NULL;
418: }
1.1.1.4 root 419: }
1.1 root 420:
1.1.1.4 root 421:
422: /*-----------------------------------------------------------------------*/
1.1.1.9 root 423: /**
424: * Set hardware configuration of RS-232 according to the USART control register.
425: *
426: * ucr: USART Control Register
427: * Bit 0: unused
428: * Bit 1: 0-Odd Parity, 1-Even Parity
429: * Bit 2: 0-No Parity, 1-Parity
430: * Bits 3,4: Start/Stop bits
431: * 0 0 : 0-Start, 0-Stop Synchronous
432: * 0 1 : 0-Start, 1-Stop Asynchronous
433: * 1 0 : 1-Start, 1.5-Stop Asynchronous
434: * 1 1 : 1-Start, 2-Stop Asynchronous
435: * Bits 5,6: 'WordLength'
436: * 0 0 : 8 Bits
437: * 0 1 : 7 Bits
438: * 1 0 : 6 Bits
439: * 1 1 : 5 Bits
440: * Bit 7: Frequency from TC and RC
441: */
1.1.1.20! root 442: static void RS232_HandleUCR(Sint16 ucr)
1.1.1.4 root 443: {
444: #if HAVE_TERMIOS_H
445: int nCharSize; /* Bits per character: 5, 6, 7 or 8 */
446: int nStopBits; /* Stop bits: 0=0 bits, 1=1 bit, 2=1.5 bits, 3=2 bits */
447:
448: nCharSize = 8 - ((ucr >> 5) & 3);
449: nStopBits = (ucr >> 3) & 3;
450:
451: Dprintf(("RS232_HandleUCR(%i) : character size=%i , stop bits=%i\n",
452: ucr, nCharSize, nStopBits));
453:
454: if (hComOut != NULL)
455: {
1.1.1.14 root 456: if (!RS232_SetBitsConfig(hComOut, nCharSize, nStopBits, ucr&4, ucr&2))
457: Log_Printf(LOG_WARN, "RS232_HandleUCR: failed to set bits configuration for %s\n", ConfigureParams.RS232.szOutFileName);
1.1.1.4 root 458: }
459:
460: if (hComIn != NULL)
461: {
1.1.1.14 root 462: if (!RS232_SetBitsConfig(hComIn, nCharSize, nStopBits, ucr&4, ucr&2))
463: Log_Printf(LOG_WARN, "RS232_HandleUCR: failed to set bits configuration for %s\n", ConfigureParams.RS232.szInFileName);
1.1.1.4 root 464: }
1.1.1.5 root 465: #endif /* HAVE_TERMIOS_H */
1.1.1.4 root 466: }
467:
468:
469: /*-----------------------------------------------------------------------*/
1.1.1.9 root 470: /**
471: * Set baud rate configuration of RS-232.
472: */
1.1.1.20! root 473: static bool RS232_SetBaudRate(int nBaud)
1.1.1.4 root 474: {
475: #if HAVE_TERMIOS_H
476: int i;
477: int fd;
478: speed_t baudtype;
479: struct termios termmode;
1.1.1.8 root 480: static const int baudtable[][2] =
1.1.1.4 root 481: {
482: { 50, B50 },
483: { 75, B75 },
484: { 110, B110 },
485: { 134, B134 },
486: { 150, B150 },
487: { 200, B200 },
488: { 300, B300 },
489: { 600, B600 },
490: { 1200, B1200 },
491: { 1800, B1800 },
492: { 2400, B2400 },
493: { 4800, B4800 },
494: { 9600, B9600 },
495: { 19200, B19200 },
496: { 38400, B38400 },
497: { 57600, B57600 },
498: { 115200, B115200 },
1.1.1.8 root 499: #ifdef B230400 /* B230400 is not defined on all systems */
1.1.1.4 root 500: { 230400, B230400 },
1.1.1.8 root 501: #endif
1.1.1.4 root 502: { -1, -1 }
503: };
504:
505: Dprintf(("RS232_SetBaudRate(%i)\n", nBaud));
506:
507: /* Convert baud number to baud termios constant: */
508: baudtype = -1;
509: for (i = 0; baudtable[i][0] != -1; i++)
510: {
511: if (baudtable[i][0] == nBaud)
512: {
513: baudtype = baudtable[i][1];
514: break;
515: }
516: }
517:
1.1.1.5 root 518: if (baudtype == (speed_t)-1)
1.1.1.4 root 519: {
520: Dprintf(("RS232_SetBaudRate: Unsupported baud rate %i.\n", nBaud));
1.1.1.13 root 521: return false;
1.1.1.4 root 522: }
523:
524: /* Set ouput speed: */
525: if (hComOut != NULL)
526: {
527: memset (&termmode, 0, sizeof(termmode)); /* Init with zeroes */
528: fd = fileno(hComOut);
529: if (isatty(fd))
530: {
531: if (tcgetattr(fd, &termmode) != 0)
1.1.1.13 root 532: return false;
1.1.1.4 root 533:
534: cfsetospeed(&termmode, baudtype);
535:
536: if (tcsetattr(fd, TCSADRAIN, &termmode) != 0)
1.1.1.13 root 537: return false;
1.1.1.4 root 538: }
539: }
540:
541: /* Set input speed: */
542: if (hComIn != NULL)
543: {
544: memset (&termmode, 0, sizeof(termmode)); /* Init with zeroes */
545: fd = fileno(hComIn);
546: if (isatty(fd))
547: {
548: if (tcgetattr(fd, &termmode) != 0)
1.1.1.13 root 549: return false;
1.1.1.4 root 550:
551: cfsetispeed(&termmode, baudtype);
552:
553: if (tcsetattr(fd, TCSADRAIN, &termmode) != 0)
1.1.1.13 root 554: return false;
1.1.1.4 root 555: }
556: }
557: #endif /* HAVE_TERMIOS_H */
558:
1.1.1.13 root 559: return true;
1.1.1.4 root 560: }
561:
562:
563: /*-----------------------------------------------------------------------*/
1.1.1.9 root 564: /**
565: * Set baud rate configuration of RS-232 according to the Timer-D hardware
566: * registers.
567: */
1.1.1.4 root 568: void RS232_SetBaudRateFromTimerD(void)
1.1 root 569: {
1.1.1.4 root 570: int nTimerD_CR, nTimerD_DR, nBaudRate;
571:
1.1.1.10 root 572: nTimerD_CR = IoMem[0xfffa1d] & 0x07;
573: nTimerD_DR = IoMem[0xfffa25];
1.1.1.4 root 574:
575: if (!nTimerD_CR)
576: return;
577:
1.1.1.13 root 578: if ( nTimerD_DR == 0 )
579: nTimerD_DR = 256; /* In MFP, a data register=0 is in fact 256 */
580:
1.1.1.4 root 581: /* Calculate baud rate: (MFP/Timer-D is supplied with 2.4576 MHz) */
582: nBaudRate = 2457600 / nTimerD_DR / 2;
1.1.1.11 root 583:
584: /*if (IoMem[0xfffa29] & 0x80)*/ /* We only support the by-16 prescaler */
585: nBaudRate /= 16;
586:
1.1.1.4 root 587: switch (nTimerD_CR)
588: {
589: case 1: nBaudRate /= 4; break;
590: case 2: nBaudRate /= 10; break;
591: case 3: nBaudRate /= 16; break;
592: case 4: nBaudRate /= 50; break;
593: case 5: nBaudRate /= 64; break;
594: case 6: nBaudRate /= 100; break;
595: case 7: nBaudRate /= 200; break;
596: }
597:
598: /* Adjust some ugly baud rates from TOS to more reasonable values: */
599: switch (nBaudRate)
600: {
601: case 80: nBaudRate = 75; break;
602: case 109: nBaudRate = 110; break;
603: case 120: nBaudRate = 110; break;
604: case 1745: nBaudRate = 1800; break;
605: case 1920: nBaudRate = 1800; break;
606: }
1.1 root 607:
1.1.1.4 root 608: RS232_SetBaudRate(nBaudRate);
609: }
610:
611:
612: /*----------------------------------------------------------------------- */
1.1.1.9 root 613: /**
614: * Pass bytes from emulator to RS-232
615: */
1.1.1.20! root 616: static bool RS232_TransferBytesTo(Uint8 *pBytes, int nBytes)
1.1 root 617: {
1.1.1.15 root 618: /* Make sure there's a RS-232 connection if it's enabled */
619: if (ConfigureParams.RS232.bEnableRS232)
620: RS232_OpenCOMPort();
1.1.1.4 root 621:
622: /* Have we connected to the RS232? */
1.1.1.17 root 623: if (hComOut)
1.1.1.4 root 624: {
625: /* Send bytes directly to the COM file */
626: if (fwrite(pBytes, 1, nBytes, hComOut))
627: {
628: Dprintf(("RS232: Sent %i bytes ($%x ...)\n", nBytes, *pBytes));
1.1.1.18 root 629: MFP_InputOnChannel ( MFP_INT_TRN_BUF_EMPTY , 0 );
1.1.1.4 root 630:
1.1.1.13 root 631: return true; /* OK */
1.1.1.4 root 632: }
633: }
634:
1.1.1.13 root 635: return false; /* Failed */
1.1.1.4 root 636: }
637:
638:
639: /*-----------------------------------------------------------------------*/
1.1.1.9 root 640: /**
641: * Read characters from our internal input buffer (bytes from other machine)
642: */
1.1.1.20! root 643: static bool RS232_ReadBytes(Uint8 *pBytes, int nBytes)
1.1.1.4 root 644: {
645: int i;
646:
647: /* Connected? */
1.1.1.17 root 648: if (hComIn && InputBuffer_Head != InputBuffer_Tail)
1.1.1.4 root 649: {
650: /* Read bytes out of input buffer */
651: for (i=0; i<nBytes; i++)
652: {
653: *pBytes++ = InputBuffer_RS232[InputBuffer_Head];
654: InputBuffer_Head = (InputBuffer_Head+1) % MAX_RS232INPUT_BUFFER;
655: SDL_SemPost(pSemFreeBuf); /* Signal free space */
656: }
1.1.1.13 root 657: return true;
1.1.1.4 root 658: }
659:
1.1.1.13 root 660: return false;
1.1.1.4 root 661: }
662:
663:
664: /*-----------------------------------------------------------------------*/
1.1.1.9 root 665: /**
1.1.1.13 root 666: * Return true if bytes waiting!
1.1.1.9 root 667: */
1.1.1.20! root 668: static bool RS232_GetStatus(void)
1.1.1.4 root 669: {
670: /* Connected? */
1.1.1.17 root 671: if (hComIn)
1.1.1.4 root 672: {
673: /* Do we have bytes in the input buffer? */
674: if (InputBuffer_Head != InputBuffer_Tail)
1.1.1.13 root 675: return true;
1.1.1.4 root 676: }
1.1 root 677:
1.1.1.4 root 678: /* No, none */
1.1.1.13 root 679: return false;
1.1.1.4 root 680: }
1.1 root 681:
682:
1.1.1.4 root 683: /*-----------------------------------------------------------------------*/
1.1.1.9 root 684: /**
685: * Read from the Syncronous Character Register.
686: */
1.1.1.4 root 687: void RS232_SCR_ReadByte(void)
1.1 root 688: {
1.1.1.8 root 689: M68000_WaitState(4);
690:
691: /* nothing */
1.1.1.4 root 692: }
693:
694: /*-----------------------------------------------------------------------*/
1.1.1.9 root 695: /**
696: * Write to the Syncronous Character Register.
697: */
1.1.1.4 root 698: void RS232_SCR_WriteByte(void)
699: {
1.1.1.8 root 700: M68000_WaitState(4);
701:
1.1.1.10 root 702: /*Dprintf(("RS232: Write to SCR: $%x\n", (int)IoMem[0xfffa27]));*/
1.1.1.4 root 703: }
1.1 root 704:
1.1.1.4 root 705:
706: /*-----------------------------------------------------------------------*/
1.1.1.9 root 707: /**
708: * Read from the USART Control Register.
709: */
1.1.1.4 root 710: void RS232_UCR_ReadByte(void)
711: {
1.1.1.8 root 712: M68000_WaitState(4);
713:
1.1.1.10 root 714: Dprintf(("RS232: Read from UCR: $%x\n", (int)IoMem[0xfffa29]));
1.1.1.4 root 715: }
1.1 root 716:
1.1.1.4 root 717: /*-----------------------------------------------------------------------*/
1.1.1.9 root 718: /**
719: * Write to the USART Control Register.
720: */
1.1.1.4 root 721: void RS232_UCR_WriteByte(void)
722: {
1.1.1.8 root 723: M68000_WaitState(4);
724:
1.1.1.10 root 725: Dprintf(("RS232: Write to UCR: $%x\n", (int)IoMem[0xfffa29]));
1.1.1.4 root 726:
1.1.1.17 root 727: RS232_HandleUCR(IoMem[0xfffa29]);
1.1 root 728: }
729:
1.1.1.4 root 730:
731: /*-----------------------------------------------------------------------*/
1.1.1.9 root 732: /**
733: * Read from the Receiver Status Register.
734: */
1.1.1.4 root 735: void RS232_RSR_ReadByte(void)
1.1 root 736: {
1.1.1.8 root 737: M68000_WaitState(4);
738:
1.1.1.4 root 739: if (RS232_GetStatus())
1.1.1.10 root 740: IoMem[0xfffa2b] |= 0x80; /* Buffer full */
1.1.1.4 root 741: else
1.1.1.10 root 742: IoMem[0xfffa2b] &= ~0x80; /* Buffer not full */
1.1.1.4 root 743:
1.1.1.10 root 744: Dprintf(("RS232: Read from RSR: $%x\n", (int)IoMem[0xfffa2b]));
1.1.1.4 root 745: }
746:
747: /*-----------------------------------------------------------------------*/
1.1.1.9 root 748: /**
749: * Write to the Receiver Status Register.
750: */
1.1.1.4 root 751: void RS232_RSR_WriteByte(void)
752: {
1.1.1.8 root 753: M68000_WaitState(4);
754:
1.1.1.10 root 755: Dprintf(("RS232: Write to RSR: $%x\n", (int)IoMem[0xfffa2b]));
1.1 root 756: }
757:
1.1.1.4 root 758:
759: /*-----------------------------------------------------------------------*/
1.1.1.9 root 760: /**
761: * Read from the Transmitter Status Register.
1.1.1.16 root 762: * When RS232 emulation is not enabled, we still return 0x80 to allow
763: * some games to work when they don't require send/receive on the RS232 port
764: * (eg : 'Treasure Trap', 'The Deep' write some debug informations to RS232)
1.1.1.9 root 765: */
1.1.1.4 root 766: void RS232_TSR_ReadByte(void)
1.1 root 767: {
1.1.1.8 root 768: M68000_WaitState(4);
769:
1.1.1.16 root 770: IoMem[0xfffa2d] |= 0x80; /* Buffer empty */
1.1 root 771:
1.1.1.10 root 772: Dprintf(("RS232: Read from TSR: $%x\n", (int)IoMem[0xfffa2d]));
1.1 root 773: }
774:
1.1.1.4 root 775: /*-----------------------------------------------------------------------*/
1.1.1.9 root 776: /**
777: * Write to the Transmitter Status Register.
778: */
1.1.1.4 root 779: void RS232_TSR_WriteByte(void)
780: {
1.1.1.8 root 781: M68000_WaitState(4);
782:
1.1.1.10 root 783: Dprintf(("RS232: Write to TSR: $%x\n", (int)IoMem[0xfffa2d]));
1.1.1.4 root 784: }
785:
786:
787: /*-----------------------------------------------------------------------*/
1.1.1.9 root 788: /**
789: * Read from the USART Data Register.
790: */
1.1.1.4 root 791: void RS232_UDR_ReadByte(void)
1.1 root 792: {
1.1.1.14 root 793: Uint8 InByte = 0;
1.1 root 794:
1.1.1.8 root 795: M68000_WaitState(4);
796:
1.1.1.4 root 797: RS232_ReadBytes(&InByte, 1);
1.1.1.10 root 798: IoMem[0xfffa2f] = InByte;
799: Dprintf(("RS232: Read from UDR: $%x\n", (int)IoMem[0xfffa2f]));
1.1.1.4 root 800:
801: if (RS232_GetStatus()) /* More data waiting? */
802: {
803: /* Yes, generate another interrupt. */
1.1.1.18 root 804: MFP_InputOnChannel ( MFP_INT_RCV_BUF_FULL , 0 );
1.1.1.4 root 805: }
1.1 root 806: }
1.1.1.4 root 807:
808: /*-----------------------------------------------------------------------*/
1.1.1.9 root 809: /**
810: * Write to the USART Data Register.
811: */
1.1.1.4 root 812: void RS232_UDR_WriteByte(void)
813: {
1.1.1.14 root 814: Uint8 OutByte;
1.1.1.4 root 815:
1.1.1.8 root 816: M68000_WaitState(4);
817:
1.1.1.10 root 818: OutByte = IoMem[0xfffa2f];
1.1.1.4 root 819: RS232_TransferBytesTo(&OutByte, 1);
1.1.1.10 root 820: Dprintf(("RS232: Write to UDR: $%x\n", (int)IoMem[0xfffa2f]));
1.1.1.4 root 821: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.