|
|
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.4 root 51: 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.13 root 307: while (true) 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.8 root 376: RS232Thread = SDL_CreateThread(RS232_ThreadFunc, NULL); 377: Dprintf(("RS232 thread has been created.\n")); 1.1.1.4 root 378: } 379: } 1.1.1.8 root 380: } 1.1.1.4 root 381: 1.1.1.8 root 382: 383: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 384: /** 385: * Close RS-232 connection and stop checking for incoming data. 386: */ 1.1.1.8 root 387: void RS232_UnInit(void) 388: { 389: /* Close, kill thread and free resource */ 390: if (RS232Thread) 391: { 1.1.1.15 root 392: /* Instead of killing the thread directly, we should 393: * probably better inform it via IPC so that it can 394: * terminate gracefully... but then we would need to 395: * wait until it exits, otherwise there's a data race 396: * on accessing/modifying hComIn. 397: */ 1.1.1.8 root 398: Dprintf(("Killing RS232 thread...\n")); 399: SDL_KillThread(RS232Thread); 400: RS232Thread = NULL; 401: } 402: RS232_CloseCOMPort(); 1.1.1.9 root 403: 1.1.1.8 root 404: if (pSemFreeBuf) 405: { 406: SDL_DestroySemaphore(pSemFreeBuf); 407: pSemFreeBuf = NULL; 408: } 1.1.1.4 root 409: } 1.1 root 410: 1.1.1.4 root 411: 412: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 413: /** 414: * Set hardware configuration of RS-232 according to the USART control register. 415: * 416: * ucr: USART Control Register 417: * Bit 0: unused 418: * Bit 1: 0-Odd Parity, 1-Even Parity 419: * Bit 2: 0-No Parity, 1-Parity 420: * Bits 3,4: Start/Stop bits 421: * 0 0 : 0-Start, 0-Stop Synchronous 422: * 0 1 : 0-Start, 1-Stop Asynchronous 423: * 1 0 : 1-Start, 1.5-Stop Asynchronous 424: * 1 1 : 1-Start, 2-Stop Asynchronous 425: * Bits 5,6: 'WordLength' 426: * 0 0 : 8 Bits 427: * 0 1 : 7 Bits 428: * 1 0 : 6 Bits 429: * 1 1 : 5 Bits 430: * Bit 7: Frequency from TC and RC 431: */ 1.1.1.14 root 432: void RS232_HandleUCR(Sint16 ucr) 1.1.1.4 root 433: { 434: #if HAVE_TERMIOS_H 435: int nCharSize; /* Bits per character: 5, 6, 7 or 8 */ 436: int nStopBits; /* Stop bits: 0=0 bits, 1=1 bit, 2=1.5 bits, 3=2 bits */ 437: 438: nCharSize = 8 - ((ucr >> 5) & 3); 439: nStopBits = (ucr >> 3) & 3; 440: 441: Dprintf(("RS232_HandleUCR(%i) : character size=%i , stop bits=%i\n", 442: ucr, nCharSize, nStopBits)); 443: 444: if (hComOut != NULL) 445: { 1.1.1.14 root 446: if (!RS232_SetBitsConfig(hComOut, nCharSize, nStopBits, ucr&4, ucr&2)) 447: Log_Printf(LOG_WARN, "RS232_HandleUCR: failed to set bits configuration for %s\n", ConfigureParams.RS232.szOutFileName); 1.1.1.4 root 448: } 449: 450: if (hComIn != NULL) 451: { 1.1.1.14 root 452: if (!RS232_SetBitsConfig(hComIn, nCharSize, nStopBits, ucr&4, ucr&2)) 453: Log_Printf(LOG_WARN, "RS232_HandleUCR: failed to set bits configuration for %s\n", ConfigureParams.RS232.szInFileName); 1.1.1.4 root 454: } 1.1.1.5 root 455: #endif /* HAVE_TERMIOS_H */ 1.1.1.4 root 456: } 457: 458: 459: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 460: /** 461: * Set baud rate configuration of RS-232. 462: */ 1.1.1.11 root 463: bool RS232_SetBaudRate(int nBaud) 1.1.1.4 root 464: { 465: #if HAVE_TERMIOS_H 466: int i; 467: int fd; 468: speed_t baudtype; 469: struct termios termmode; 1.1.1.8 root 470: static const int baudtable[][2] = 1.1.1.4 root 471: { 472: { 50, B50 }, 473: { 75, B75 }, 474: { 110, B110 }, 475: { 134, B134 }, 476: { 150, B150 }, 477: { 200, B200 }, 478: { 300, B300 }, 479: { 600, B600 }, 480: { 1200, B1200 }, 481: { 1800, B1800 }, 482: { 2400, B2400 }, 483: { 4800, B4800 }, 484: { 9600, B9600 }, 485: { 19200, B19200 }, 486: { 38400, B38400 }, 487: { 57600, B57600 }, 488: { 115200, B115200 }, 1.1.1.8 root 489: #ifdef B230400 /* B230400 is not defined on all systems */ 1.1.1.4 root 490: { 230400, B230400 }, 1.1.1.8 root 491: #endif 1.1.1.4 root 492: { -1, -1 } 493: }; 494: 495: Dprintf(("RS232_SetBaudRate(%i)\n", nBaud)); 496: 497: /* Convert baud number to baud termios constant: */ 498: baudtype = -1; 499: for (i = 0; baudtable[i][0] != -1; i++) 500: { 501: if (baudtable[i][0] == nBaud) 502: { 503: baudtype = baudtable[i][1]; 504: break; 505: } 506: } 507: 1.1.1.5 root 508: if (baudtype == (speed_t)-1) 1.1.1.4 root 509: { 510: Dprintf(("RS232_SetBaudRate: Unsupported baud rate %i.\n", nBaud)); 1.1.1.13 root 511: return false; 1.1.1.4 root 512: } 513: 514: /* Set ouput speed: */ 515: if (hComOut != NULL) 516: { 517: memset (&termmode, 0, sizeof(termmode)); /* Init with zeroes */ 518: fd = fileno(hComOut); 519: if (isatty(fd)) 520: { 521: if (tcgetattr(fd, &termmode) != 0) 1.1.1.13 root 522: return false; 1.1.1.4 root 523: 524: cfsetospeed(&termmode, baudtype); 525: 526: if (tcsetattr(fd, TCSADRAIN, &termmode) != 0) 1.1.1.13 root 527: return false; 1.1.1.4 root 528: } 529: } 530: 531: /* Set input speed: */ 532: if (hComIn != NULL) 533: { 534: memset (&termmode, 0, sizeof(termmode)); /* Init with zeroes */ 535: fd = fileno(hComIn); 536: if (isatty(fd)) 537: { 538: if (tcgetattr(fd, &termmode) != 0) 1.1.1.13 root 539: return false; 1.1.1.4 root 540: 541: cfsetispeed(&termmode, baudtype); 542: 543: if (tcsetattr(fd, TCSADRAIN, &termmode) != 0) 1.1.1.13 root 544: return false; 1.1.1.4 root 545: } 546: } 547: #endif /* HAVE_TERMIOS_H */ 548: 1.1.1.13 root 549: return true; 1.1.1.4 root 550: } 551: 552: 553: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 554: /** 555: * Set baud rate configuration of RS-232 according to the Timer-D hardware 556: * registers. 557: */ 1.1.1.4 root 558: void RS232_SetBaudRateFromTimerD(void) 1.1 root 559: { 1.1.1.4 root 560: int nTimerD_CR, nTimerD_DR, nBaudRate; 561: 1.1.1.10 root 562: nTimerD_CR = IoMem[0xfffa1d] & 0x07; 563: nTimerD_DR = IoMem[0xfffa25]; 1.1.1.4 root 564: 565: if (!nTimerD_CR) 566: return; 567: 1.1.1.13 root 568: if ( nTimerD_DR == 0 ) 569: nTimerD_DR = 256; /* In MFP, a data register=0 is in fact 256 */ 570: 1.1.1.4 root 571: /* Calculate baud rate: (MFP/Timer-D is supplied with 2.4576 MHz) */ 572: nBaudRate = 2457600 / nTimerD_DR / 2; 1.1.1.11 root 573: 574: /*if (IoMem[0xfffa29] & 0x80)*/ /* We only support the by-16 prescaler */ 575: nBaudRate /= 16; 576: 1.1.1.4 root 577: switch (nTimerD_CR) 578: { 579: case 1: nBaudRate /= 4; break; 580: case 2: nBaudRate /= 10; break; 581: case 3: nBaudRate /= 16; break; 582: case 4: nBaudRate /= 50; break; 583: case 5: nBaudRate /= 64; break; 584: case 6: nBaudRate /= 100; break; 585: case 7: nBaudRate /= 200; break; 586: } 587: 588: /* Adjust some ugly baud rates from TOS to more reasonable values: */ 589: switch (nBaudRate) 590: { 591: case 80: nBaudRate = 75; break; 592: case 109: nBaudRate = 110; break; 593: case 120: nBaudRate = 110; break; 594: case 1745: nBaudRate = 1800; break; 595: case 1920: nBaudRate = 1800; break; 596: } 1.1 root 597: 1.1.1.4 root 598: RS232_SetBaudRate(nBaudRate); 599: } 600: 601: 602: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 603: /** 604: * Set flow control configuration of RS-232. 605: */ 1.1.1.14 root 606: void RS232_SetFlowControl(Sint16 ctrl) 1.1.1.4 root 607: { 608: Dprintf(("RS232_SetFlowControl(%i)\n", ctrl)); 609: 610: /* Not yet written */ 1.1 root 611: } 612: 1.1.1.4 root 613: 614: /*----------------------------------------------------------------------- */ 1.1.1.9 root 615: /** 616: * Pass bytes from emulator to RS-232 617: */ 1.1.1.14 root 618: bool RS232_TransferBytesTo(Uint8 *pBytes, int nBytes) 1.1 root 619: { 1.1.1.15 root 620: /* Make sure there's a RS-232 connection if it's enabled */ 621: if (ConfigureParams.RS232.bEnableRS232) 622: RS232_OpenCOMPort(); 1.1.1.4 root 623: 624: /* Have we connected to the RS232? */ 1.1.1.17 root 625: if (hComOut) 1.1.1.4 root 626: { 627: /* Send bytes directly to the COM file */ 628: if (fwrite(pBytes, 1, nBytes, hComOut)) 629: { 630: Dprintf(("RS232: Sent %i bytes ($%x ...)\n", nBytes, *pBytes)); 1.1.1.18! root 631: MFP_InputOnChannel ( MFP_INT_TRN_BUF_EMPTY , 0 ); 1.1.1.4 root 632: 1.1.1.13 root 633: return true; /* OK */ 1.1.1.4 root 634: } 635: } 636: 1.1.1.13 root 637: return false; /* Failed */ 1.1.1.4 root 638: } 639: 640: 641: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 642: /** 643: * Read characters from our internal input buffer (bytes from other machine) 644: */ 1.1.1.14 root 645: bool RS232_ReadBytes(Uint8 *pBytes, int nBytes) 1.1.1.4 root 646: { 647: int i; 648: 649: /* Connected? */ 1.1.1.17 root 650: if (hComIn && InputBuffer_Head != InputBuffer_Tail) 1.1.1.4 root 651: { 652: /* Read bytes out of input buffer */ 653: for (i=0; i<nBytes; i++) 654: { 655: *pBytes++ = InputBuffer_RS232[InputBuffer_Head]; 656: InputBuffer_Head = (InputBuffer_Head+1) % MAX_RS232INPUT_BUFFER; 657: SDL_SemPost(pSemFreeBuf); /* Signal free space */ 658: } 1.1.1.13 root 659: return true; 1.1.1.4 root 660: } 661: 1.1.1.13 root 662: return false; 1.1.1.4 root 663: } 664: 665: 666: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 667: /** 1.1.1.13 root 668: * Return true if bytes waiting! 1.1.1.9 root 669: */ 1.1.1.11 root 670: bool RS232_GetStatus(void) 1.1.1.4 root 671: { 672: /* Connected? */ 1.1.1.17 root 673: if (hComIn) 1.1.1.4 root 674: { 675: /* Do we have bytes in the input buffer? */ 676: if (InputBuffer_Head != InputBuffer_Tail) 1.1.1.13 root 677: return true; 1.1.1.4 root 678: } 1.1 root 679: 1.1.1.4 root 680: /* No, none */ 1.1.1.13 root 681: return false; 1.1.1.4 root 682: } 1.1 root 683: 684: 1.1.1.4 root 685: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 686: /** 687: * Read from the Syncronous Character Register. 688: */ 1.1.1.4 root 689: void RS232_SCR_ReadByte(void) 1.1 root 690: { 1.1.1.8 root 691: M68000_WaitState(4); 692: 693: /* nothing */ 1.1.1.4 root 694: } 695: 696: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 697: /** 698: * Write to the Syncronous Character Register. 699: */ 1.1.1.4 root 700: void RS232_SCR_WriteByte(void) 701: { 1.1.1.8 root 702: M68000_WaitState(4); 703: 1.1.1.10 root 704: /*Dprintf(("RS232: Write to SCR: $%x\n", (int)IoMem[0xfffa27]));*/ 1.1.1.4 root 705: } 1.1 root 706: 1.1.1.4 root 707: 708: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 709: /** 710: * Read from the USART Control Register. 711: */ 1.1.1.4 root 712: void RS232_UCR_ReadByte(void) 713: { 1.1.1.8 root 714: M68000_WaitState(4); 715: 1.1.1.10 root 716: Dprintf(("RS232: Read from UCR: $%x\n", (int)IoMem[0xfffa29])); 1.1.1.4 root 717: } 1.1 root 718: 1.1.1.4 root 719: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 720: /** 721: * Write to the USART Control Register. 722: */ 1.1.1.4 root 723: void RS232_UCR_WriteByte(void) 724: { 1.1.1.8 root 725: M68000_WaitState(4); 726: 1.1.1.10 root 727: Dprintf(("RS232: Write to UCR: $%x\n", (int)IoMem[0xfffa29])); 1.1.1.4 root 728: 1.1.1.17 root 729: RS232_HandleUCR(IoMem[0xfffa29]); 1.1 root 730: } 731: 1.1.1.4 root 732: 733: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 734: /** 735: * Read from the Receiver Status Register. 736: */ 1.1.1.4 root 737: void RS232_RSR_ReadByte(void) 1.1 root 738: { 1.1.1.8 root 739: M68000_WaitState(4); 740: 1.1.1.4 root 741: if (RS232_GetStatus()) 1.1.1.10 root 742: IoMem[0xfffa2b] |= 0x80; /* Buffer full */ 1.1.1.4 root 743: else 1.1.1.10 root 744: IoMem[0xfffa2b] &= ~0x80; /* Buffer not full */ 1.1.1.4 root 745: 1.1.1.10 root 746: Dprintf(("RS232: Read from RSR: $%x\n", (int)IoMem[0xfffa2b])); 1.1.1.4 root 747: } 748: 749: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 750: /** 751: * Write to the Receiver Status Register. 752: */ 1.1.1.4 root 753: void RS232_RSR_WriteByte(void) 754: { 1.1.1.8 root 755: M68000_WaitState(4); 756: 1.1.1.10 root 757: Dprintf(("RS232: Write to RSR: $%x\n", (int)IoMem[0xfffa2b])); 1.1 root 758: } 759: 1.1.1.4 root 760: 761: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 762: /** 763: * Read from the Transmitter Status Register. 1.1.1.16 root 764: * When RS232 emulation is not enabled, we still return 0x80 to allow 765: * some games to work when they don't require send/receive on the RS232 port 766: * (eg : 'Treasure Trap', 'The Deep' write some debug informations to RS232) 1.1.1.9 root 767: */ 1.1.1.4 root 768: void RS232_TSR_ReadByte(void) 1.1 root 769: { 1.1.1.8 root 770: M68000_WaitState(4); 771: 1.1.1.16 root 772: IoMem[0xfffa2d] |= 0x80; /* Buffer empty */ 1.1 root 773: 1.1.1.10 root 774: Dprintf(("RS232: Read from TSR: $%x\n", (int)IoMem[0xfffa2d])); 1.1 root 775: } 776: 1.1.1.4 root 777: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 778: /** 779: * Write to the Transmitter Status Register. 780: */ 1.1.1.4 root 781: void RS232_TSR_WriteByte(void) 782: { 1.1.1.8 root 783: M68000_WaitState(4); 784: 1.1.1.10 root 785: Dprintf(("RS232: Write to TSR: $%x\n", (int)IoMem[0xfffa2d])); 1.1.1.4 root 786: } 787: 788: 789: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 790: /** 791: * Read from the USART Data Register. 792: */ 1.1.1.4 root 793: void RS232_UDR_ReadByte(void) 1.1 root 794: { 1.1.1.14 root 795: Uint8 InByte = 0; 1.1 root 796: 1.1.1.8 root 797: M68000_WaitState(4); 798: 1.1.1.4 root 799: RS232_ReadBytes(&InByte, 1); 1.1.1.10 root 800: IoMem[0xfffa2f] = InByte; 801: Dprintf(("RS232: Read from UDR: $%x\n", (int)IoMem[0xfffa2f])); 1.1.1.4 root 802: 803: if (RS232_GetStatus()) /* More data waiting? */ 804: { 805: /* Yes, generate another interrupt. */ 1.1.1.18! root 806: MFP_InputOnChannel ( MFP_INT_RCV_BUF_FULL , 0 ); 1.1.1.4 root 807: } 1.1 root 808: } 1.1.1.4 root 809: 810: /*-----------------------------------------------------------------------*/ 1.1.1.9 root 811: /** 812: * Write to the USART Data Register. 813: */ 1.1.1.4 root 814: void RS232_UDR_WriteByte(void) 815: { 1.1.1.14 root 816: Uint8 OutByte; 1.1.1.4 root 817: 1.1.1.8 root 818: M68000_WaitState(4); 819: 1.1.1.10 root 820: OutByte = IoMem[0xfffa2f]; 1.1.1.4 root 821: RS232_TransferBytesTo(&OutByte, 1); 1.1.1.10 root 822: Dprintf(("RS232: Write to UDR: $%x\n", (int)IoMem[0xfffa2f])); 1.1.1.4 root 823: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.