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