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