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

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

unix.superglobalmegacorp.com

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