|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.