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

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.3 ! root      392:     if (sd != 0)
1.1       root      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.