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