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

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

unix.superglobalmegacorp.com

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