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

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

unix.superglobalmegacorp.com

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