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