Annotation of uae/src/serial.c, revision 1.1.1.4

1.1.1.3   root        1:  /*
1.1       root        2:   * UAE - The Un*x Amiga Emulator
1.1.1.3   root        3:   *
1.1       root        4:   *  Serial Line Emulation
                      5:   *
1.1.1.3   root        6:   * (c) 1996, 1997 Stefan Reinauer <[email protected]>
                      7:   * (c) 1997 Christian Schmitt <[email protected]>
                      8:   *
1.1       root        9:   */
                     10: 
                     11: #include "sysconfig.h"
                     12: #include "sysdeps.h"
                     13: 
                     14: #include "config.h"
                     15: #include "options.h"
1.1.1.3   root       16: #include "uae.h"
1.1       root       17: #include "memory.h"
                     18: #include "custom.h"
1.1.1.2   root       19: #include "readcpu.h"
1.1       root       20: #include "newcpu.h"
1.1.1.3   root       21: #include "cia.h"
                     22: 
                     23: #undef POSIX_SERIAL
                     24: /* Some more or less good way to determine whether we can safely compile in
                     25:  * the serial stuff. I'm certain it breaks compilation on some systems. */
                     26: #if defined HAVE_SYS_TERMIOS_H && defined HAVE_POSIX_OPT_H && defined HAVE_SYS_IOCTL_H && defined HAVE_TCGETATTR
                     27: #define POSIX_SERIAL
                     28: #endif
                     29: 
                     30: #ifdef POSIX_SERIAL
                     31: #include <termios.h>
                     32: #include <unistd.h>
                     33: #include <sys/ioctl.h>
                     34: #endif
                     35: 
                     36: #if !defined B300 || !defined B1200 || !defined B2400 || !defined B4800 || !defined B9600
                     37: #undef POSIX_SERIAL
                     38: #endif
                     39: #if !defined B19200 || !defined B57600 || !defined B115200 || !defined B230400
                     40: #undef POSIX_SERIAL
                     41: #endif
1.1       root       42: 
1.1.1.2   root       43: #ifndef O_NONBLOCK
                     44: #define O_NONBLOCK O_NDELAY
                     45: #endif
                     46: 
1.1.1.3   root       47: #define SERIALDEBUG 1 /* 0, 1, 2 3 */
                     48: #define MODEMTEST   0 /* 0 or 1 */
1.1       root       49: 
1.1.1.3   root       50: void serial_open (void);
                     51: void serial_close (void);
                     52: void serial_init (void);
                     53: void serial_exit (void);
                     54: 
                     55: void serial_dtr_on (void);
                     56: void serial_dtr_off (void);
                     57: 
                     58: void serial_flush_buffer (void);
                     59: static int serial_read (char *buffer);
                     60: 
                     61: int serial_readstatus (void);
                     62: uae_u16 serial_writestatus (int, int);
                     63: 
                     64: uae_u16 SERDATR (void);
                     65: 
                     66: int  SERDATS (void);
                     67: void  SERPER (uae_u16 w);
                     68: void  SERDAT (uae_u16 w);
                     69: 
                     70: static char inbuf[1024], outbuf[1024];
                     71: static int inptr, inlast, outlast;
                     72: 
                     73: int waitqueue=0,
                     74:     carrier=0,
                     75:     serdev=0,
                     76:     dsr=0,
                     77:     dtr=0,
                     78:     isbaeh=0,
                     79:     doreadser=0,
                     80:     serstat=-1;
1.1       root       81: 
                     82: int sd = -1;
                     83: 
1.1.1.3   root       84: #ifdef POSIX_SERIAL
                     85:     struct termios tios;
                     86: #endif
                     87: 
                     88: uae_u16 serper=0,serdat;
1.1       root       89: 
1.1.1.3   root       90: void SERPER (uae_u16 w)
1.1       root       91: {
1.1.1.3   root       92:     int baud=0, pspeed;
                     93: 
                     94:     if (!currprefs.use_serial)
1.1       root       95:        return;
                     96: 
1.1.1.3   root       97: #if defined POSIX_SERIAL
                     98:     if (serper == w)  /* don't set baudrate if it's already ok */
                     99:        return;
                    100:     serper=w;
                    101: 
                    102:     if (w&0x8000)
                    103:        fprintf (stdout, "SERPER: 9bit transmission not implemented.\n");
                    104: 
                    105:     switch (w & 0x7fff) {
                    106:      /* These values should be calculated by the current
                    107:       * color clock value (NTSC/PAL). But this solution is
                    108:       * easy and it works.
                    109:       */
                    110: 
                    111:      case 0x2e9b:
                    112:      case 0x2e14: baud=300; pspeed=B300; break;
                    113:      case 0x170a:
                    114:      case 0x0b85: baud=1200; pspeed=B1200; break;
                    115:      case 0x05c2:
                    116:      case 0x05b9: baud=2400; pspeed=B2400; break;
                    117:      case 0x02e9:
                    118:      case 0x02e1: baud=4800; pspeed=B4800; break;
                    119:      case 0x0174:
                    120:      case 0x0170: baud=9600; pspeed=B9600; break;
                    121:      case 0x00b9:
                    122:      case 0x00b8: baud=19200; pspeed=B19200; break;
                    123:      case 0x005c:
                    124:      case 0x005d: baud=38400; pspeed=B38400; break;
                    125:      case 0x003d: baud=57600; pspeed=B57600; break;
                    126:      case 0x001e: baud=115200; pspeed=B115200; break;
                    127:      case 0x000f: baud=230400; pspeed=B230400; break;
1.1       root      128:      default:
1.1.1.3   root      129:        fprintf (stdout,"SERPER: unsupported baudrate (0x%04x) %d\n",w&0x7fff,
                    130:                 (unsigned int)(3579546.471/(double)((w&0x7fff)+1)));  return;
1.1       root      131:     }
1.1.1.3   root      132: 
                    133:     /* Only access hardware when we own it */
                    134:     if (serdev == 1) {
                    135:        if (tcgetattr (sd, &tios) < 0) {
                    136:            fprintf (stderr, "SERPER: TCGETATTR failed\n");
                    137:            return;
                    138:        }
                    139: 
                    140:        if (cfsetispeed (&tios, pspeed) < 0) {    /* set serial input speed */
                    141:            fprintf (stderr, "SERPER: CFSETISPEED (%d bps) failed\n", baud);
                    142:            return;
                    143:        }
                    144:        if (cfsetospeed (&tios, pspeed) < 0) {    /* set serial output speed */
                    145:            fprintf (stderr, "SERPER: CFSETOSPEED (%d bps) failed\n", baud);
                    146:            return;
                    147:        }
                    148: 
                    149:        if (tcsetattr (sd, TCSADRAIN, &tios) < 0) {
                    150:            fprintf (stderr, "SERPER: TCSETATTR failed\n");
                    151:            return;
                    152:        }
1.1       root      153:     }
                    154: #endif
1.1.1.3   root      155: 
                    156: #if SERIALDEBUG > 0
                    157:     if (serdev == 1)
                    158:        fprintf (stdout, "SERPER: baudrate set to %d bit/sec\n", baud);
                    159: #endif
1.1       root      160: }
                    161: 
1.1.1.3   root      162: /* Not (fully) implemented yet:
                    163:  *
                    164:  *  -  Something's wrong with the Interrupts.
                    165:  *     (NComm works, TERM does not. TERM switches to a
                    166:  *     blind mode after a connect and wait's for the end
                    167:  *     of an asynchronous read before switching blind
                    168:  *     mode off again. It never gets there on UAE :-< )
                    169:  *
                    170:  *  -  RTS/CTS handshake, this is not really neccessary,
                    171:  *     because you can use RTS/CTS "outside" without
                    172:  *     passing it through to the emulated Amiga
                    173:  *
                    174:  *  -  ADCON-Register ($9e write, $10 read) Bit 11 (UARTBRK)
                    175:  *     (see "Amiga Intern", pg 246)
                    176:  */
                    177: 
                    178: void SERDAT (uae_u16 w)
1.1       root      179: {
1.1.1.3   root      180:     unsigned char z;
                    181: 
                    182:     if (!currprefs.use_serial)
                    183:        return;
                    184: 
                    185:     z = (unsigned char)(w&0xff);
1.1       root      186: 
1.1.1.3   root      187:     if (currprefs.serial_demand && !dtr) {
                    188:        if (!isbaeh) {
                    189:            fprintf(stdout,"SERDAT: Baeh.. Your software needs SERIAL_ALWAYS to work properly.\n");
                    190:            isbaeh=1;
                    191:        }
1.1       root      192:        return;
1.1.1.3   root      193:     } else {
                    194:        outbuf[outlast++] = z;
                    195:        if (outlast == sizeof outbuf)
                    196:            serial_flush_buffer();
                    197:     }
                    198: 
                    199: #if SERIALDEBUG > 2
                    200:     fprintf (stderr, "SERDAT: wrote 0x%04x\n", w);
                    201: #endif
1.1       root      202: 
1.1.1.3   root      203:     serdat|=0x2000; /* Set TBE in the SERDATR ... */
                    204:     intreq|=1;      /* ... and in INTREQ register */
1.1       root      205:     return;
                    206: }
                    207: 
1.1.1.3   root      208: uae_u16 SERDATR (void)
                    209: {
                    210:     if (!currprefs.use_serial)
                    211:        return 0;
                    212: #if SERIALDEBUG > 2
                    213:     fprintf (stdout, "SERDATR: read 0x%04x\n", serdat);
                    214: #endif
                    215:     waitqueue = 0;
                    216:     return serdat;
                    217: }
                    218: 
                    219: int SERDATS (void)
1.1       root      220: {
1.1.1.3   root      221:     unsigned char z;
1.1       root      222: 
1.1.1.3   root      223:     if (!serdev)           /* || (serdat&0x4000)) */
1.1.1.2   root      224:        return 0;
1.1       root      225: 
1.1.1.3   root      226:     if (waitqueue == 1) {
                    227:        intreq |= 0x0800;
                    228:        return 1;
                    229:     }
                    230: 
                    231:     if ((serial_read ((char *)&z)) == 1) {
                    232:        waitqueue = 1;
                    233:        serdat = 0x4100; /* RBF and STP set! */
                    234:        serdat |= ((unsigned int)z) & 0xff;
                    235:        intreq |= 0x0800; /* Set RBF flag (Receive Buffer full) */
                    236: 
                    237: #if SERIALDEBUG > 1
                    238:        fprintf (stdout, "SERDATS: received 0x%02x --> serdat==0x%04x\n",
                    239:                 (unsigned int)z, (unsigned int)serdat);
1.1       root      240: #endif
1.1.1.3   root      241:        return 1;
1.1       root      242:     }
1.1.1.3   root      243:     return 0;
                    244: }
                    245: 
                    246: void serial_dtr_on(void)
                    247: {
                    248: #if SERIALDEBUG > 0
                    249:     fprintf (stdout, "DTR on.\n");
                    250: #endif
                    251:     dtr=1;
                    252: 
                    253:     if (currprefs.serial_demand)
                    254:        serial_open ();
1.1       root      255: }
                    256: 
1.1.1.3   root      257: void serial_dtr_off(void)
1.1       root      258: {
1.1.1.3   root      259: #if SERIALDEBUG > 0
                    260:     fprintf (stdout, "DTR off.\n");
                    261: #endif
                    262:     dtr=0;
                    263:     if (currprefs.serial_demand)
                    264:        serial_close ();
                    265: }
                    266: 
                    267: static int serial_read (char *buffer)
                    268: {
                    269:     if (inptr < inlast) {
                    270:        *buffer = inbuf[inptr++];
                    271:        return 1;
                    272:     }
                    273: 
                    274:     if (serdev == 1) {
                    275:        inlast = read (sd, inbuf, sizeof inbuf);
                    276:        inptr = 0;
                    277:        if (inptr < inlast) {
                    278:            *buffer = inbuf[inptr++];
                    279:            return 1;
                    280:        }
                    281:     }
                    282: 
                    283:     return 0;
                    284: }
                    285: 
                    286: void serial_flush_buffer(void)
                    287: {
                    288:     if (serdev == 1) {
                    289:        if (outlast) {
                    290:            if (sd != 0) {
                    291:                write (sd, outbuf, outlast);
                    292:            }
                    293:        }
                    294:        outlast = 0;
                    295:     } else {
                    296:       outlast = 0;
                    297:       inptr = 0;
                    298:       inlast = 0;
                    299:     }
                    300: }
                    301: 
                    302: int serial_readstatus(void)
                    303: {
                    304:     int status = 0;
                    305: 
                    306: #ifdef POSIX_SERIAL
                    307:     ioctl (sd, TIOCMGET, &status);
                    308: 
                    309:     if (status & TIOCM_CAR) {
                    310:        if (!carrier) {
                    311:            ciabpra |= 0x20; /* Push up Carrier Detect line */
                    312:            carrier = 1;
                    313: #if SERIALDEBUG > 0
                    314:            fprintf (stdout, "Carrier detect.\n");
                    315: #endif
                    316:        }
                    317:     } else {
                    318:        if (carrier) {
                    319:            ciabpra &= ~0x20;
                    320:            carrier = 0;
                    321: #if SERIALDEBUG > 0
                    322:            fprintf (stdout, "Carrier lost.\n");
                    323: #endif
                    324:        }
                    325:     }
                    326: 
                    327:     if (status & TIOCM_DSR) {
                    328:        if (!dsr) {
                    329:            ciabpra |= 0x08; /* DSR ON */
                    330:            dsr = 1;
                    331:        }
                    332:     } else {
                    333:        if (dsr) {
                    334:            ciabpra &= ~0x08;
                    335:            dsr = 0;
                    336:        }
                    337:     }
                    338: #endif
                    339:     return status;
                    340: }
                    341: 
                    342: uae_u16 serial_writestatus (int old, int nw)
                    343: {
                    344:     if ((old & 0x80) == 0x80 && (nw & 0x80) == 0x00)
                    345:        serial_dtr_on();
                    346:     if ((old & 0x80) == 0x00 && (nw & 0x80) == 0x80)
                    347:        serial_dtr_off();
                    348: 
                    349:     if ((old & 0x40) != (nw & 0x40))
                    350:        fprintf (stdout, "RTS %s.\n", ((nw & 0x40) == 0x40) ? "set" : "cleared");
                    351: 
                    352:     if ((old & 0x10) != (nw & 0x10))
                    353:        fprintf (stdout, "CTS %s.\n", ((nw & 0x10) == 0x10) ? "set" : "cleared");
                    354: 
                    355:     return nw; /* This value could also be changed here */
                    356: }
                    357: 
                    358: void serial_open(void)
                    359: {
                    360:     if (serdev == 1)
                    361:        return;
                    362: 
                    363:     if ((sd = open (sername, O_RDWR|O_NONBLOCK|O_BINARY, 0)) < 0) {
                    364:        fprintf (stdout, "Error: Could not open Device %s\n", sername);
                    365:        return;
                    366:     }
                    367: 
                    368:     serdev = 1;
                    369: 
                    370: #ifdef POSIX_SERIAL
                    371:     if (tcgetattr (sd, &tios) < 0) {           /* Initialize Serial tty */
                    372:        fprintf (stderr, "Serial: TCGETATTR failed\n");
1.1       root      373:        return;
1.1.1.3   root      374:     }
                    375:     cfmakeraw (&tios);
1.1       root      376: 
1.1.1.3   root      377: #ifndef MODEMTEST
                    378:     tios.c_cflag &= ~CRTSCTS; /* Disable RTS/CTS */
1.1       root      379: #else
1.1.1.3   root      380:     tios.c_cflag |= CRTSCTS; /* Enabled for testing modems */
                    381: #endif
                    382: 
                    383:     if (tcsetattr (sd, TCSADRAIN, &tios) < 0) {
                    384:        fprintf (stderr,"Serial: TCSETATTR failed\n");
                    385:        return;
                    386:     }
1.1       root      387: #endif
                    388: }
                    389: 
1.1.1.3   root      390: void serial_close (void)
1.1       root      391: {
1.1.1.4 ! root      392:     if (sd >= 0)
        !           393:        close (sd);
1.1.1.3   root      394:     serdev = 0;
                    395: }
                    396: 
                    397: void serial_init (void)
                    398: {
                    399:     if (!currprefs.use_serial)
                    400:        return;
                    401: 
                    402:     if (!currprefs.serial_demand)
                    403:        serial_open ();
                    404: 
                    405:     serdat = 0x2000;
1.1       root      406:     return;
                    407: }
1.1.1.3   root      408: 
                    409: void serial_exit (void)
                    410: {
                    411:     serial_close ();   /* serial_close can always be called because it */
                    412:     dtr = 0;           /* just closes *opened* filehandles which is ok */
                    413:     return;            /* when exiting.                                */
                    414: }

unix.superglobalmegacorp.com

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