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

1.1       root        1: /*
1.1.1.4   root        2:   Hatari - rs232.c
1.1       root        3: 
1.1.1.4   root        4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   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? */
                    319:                                MFP_InputOnChannel(MFP_RCVBUFFULL_BIT, MFP_IERA, &MFP_IPRA);
                    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));
                    631:                        MFP_InputOnChannel(MFP_TRNBUFEMPTY_BIT, MFP_IERA, &MFP_IPRA);
                    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. */
                    806:                MFP_InputOnChannel(MFP_RCVBUFFULL_BIT, MFP_IERA, &MFP_IPRA);
                    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: }

unix.superglobalmegacorp.com

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