Annotation of hatari/src/rs232.c, revision 1.1.1.20

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.