1 /* scp_tty.c: Operating system-dependent terminal I/O routines.
2 
3    Copyright 1994-1997,
4    Robert M Supnik, Digital Equipment Corporation
5    Commercial use prohibited
6 
7    25-Jan-97	RMS	Added POSIX terminal I/O support
8    02-Jan-97	RMS	Fixed bug in sim_poll_kbd
9 
10    ttinit	-	called once to get initial terminal state
11    ttrunstate	-	called to put terminal into run state
12    ttcmdstate	-	called to return terminal to command state
13    ttclose	-	called once before the simulator exits
14    sim_poll_kbd	-	poll for keyboard input
15    sim_putchar -	output character to terminal
16 
17    Versions are included for generic (BSD) UNIX and for VMS.
18    The generic UNIX version works with LINUX.
19 */
20 /* #include <inttypes.h> XXX Solaris 2.6 needs this now?? grrr.... */
21 
22 #include "sim_defs.h"
23 int32 sim_int_char = 005;				/* interrupt character */
24 
25 /* VMS routines */
26 
27 #ifdef VMS
28 #define __TTYROUTINES 0
29 #include <descrip.h>
30 #include <ttdef.h>
31 #include <tt2def.h>
32 #include <iodef.h>
33 #include <ssdef.h>
34 #include <starlet.h>
35 #define EFN 0
36 unsigned int32 tty_chan = 0;
37 typedef struct {
38 	unsigned short sense_count;
39 	unsigned char sense_first_char;
40 	unsigned char sense_reserved;
41 	unsigned int32 stat;
42 	unsigned int32 stat2; } SENSE_BUF;
43 typedef struct {
44 	unsigned int16 status;
45 	unsigned int16 count;
46 	unsigned int32 dev_status; } IOSB;
47 SENSE_BUF cmd_mode = { 0 };
48 SENSE_BUF run_mode = { 0 };
49 
ttinit(void)50 t_stat ttinit (void)
51 {
52 unsigned int32 status;
53 IOSB iosb;
54 $DESCRIPTOR (terminal_device, "tt");
55 
56 status = sys$assign (&terminal_device, &tty_chan, 0, 0);
57 if (status != SS$_NORMAL) return SCPE_TTIERR;
58 status = sys$qiow (EFN, tty_chan, IO$_SENSEMODE, &iosb, 0, 0,
59 	&cmd_mode, sizeof (cmd_mode), 0, 0, 0, 0);
60 if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR;
61 run_mode = cmd_mode;
62 run_mode.stat = cmd_mode.stat | TT$M_NOECHO & ~(TT$M_HOSTSYNC | TT$M_TTSYNC);
63 run_mode.stat2 = cmd_mode.stat2 | TT2$M_PASTHRU;
64 return SCPE_OK;
65 }
66 
ttrunstate(void)67 t_stat ttrunstate (void)
68 {
69 unsigned int status;
70 IOSB iosb;
71 
72 status = sys$qiow (EFN, tty_chan, IO$_SETMODE, &iosb, 0, 0,
73 	&run_mode, sizeof (run_mode), 0, 0, 0, 0);
74 if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR;
75 return SCPE_OK;
76 }
77 
ttcmdstate(void)78 t_stat ttcmdstate (void)
79 {
80 unsigned int status;
81 IOSB iosb;
82 
83 status = sys$qiow (EFN, tty_chan, IO$_SETMODE, &iosb, 0, 0,
84 	&cmd_mode, sizeof (cmd_mode), 0, 0, 0, 0);
85 if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR;
86 return SCPE_OK;
87 }
88 
ttclose(void)89 t_stat ttclose (void)
90 {
91 return ttcmdstate ();
92 }
93 
sim_poll_kbd(void)94 t_stat sim_poll_kbd (void)
95 {
96 unsigned int status, term[2];
97 unsigned char buf[4];
98 IOSB iosb;
99 SENSE_BUF sense;
100 
101 term[0] = 0; term[1] = 0;
102 status = sys$qiow (EFN, tty_chan, IO$_SENSEMODE | IO$M_TYPEAHDCNT, &iosb,
103 	0, 0, &sense, 8, 0, term, 0, 0);
104 if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTIERR;
105 if (sense.sense_count == 0) return SCPE_OK;
106 term[0] = 0; term[1] = 0;
107 status = sys$qiow (EFN, tty_chan,
108 	IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED | IO$M_TRMNOECHO,
109 	&iosb, 0, 0, buf, 1, 0, term, 0, 0);
110 if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_OK;
111 if (buf[0] == sim_int_char) return SCPE_STOP;
112 return (buf[0] | SCPE_KFLAG);
113 }
114 
sim_putchar(int32 out)115 t_stat sim_putchar (int32 out)
116 {
117 unsigned int status;
118 char c;
119 IOSB iosb;
120 
121 c = out;
122 status = sys$qiow (EFN, tty_chan, IO$_WRITELBLK | IO$M_NOFORMAT,
123 	&iosb, 0, 0, &c, 1, 0, 0, 0, 0);
124 if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_TTOERR;
125 return SCPE_OK;
126 }
127 #endif
128 
129 /* Win32 routines */
130 
131 #ifdef _WIN32
132 #define __TTYROUTINES 0
133 #include <conio.h>
134 
ttinit(void)135 t_stat ttinit (void)
136 {
137 return SCPE_OK;
138 }
139 
ttrunstate(void)140 t_stat ttrunstate (void)
141 {
142 return SCPE_OK;
143 }
144 
ttcmdstate(void)145 t_stat ttcmdstate (void)
146 {
147 return SCPE_OK;
148 }
149 
ttclose(void)150 t_stat ttclose (void)
151 {
152 return SCPE_OK;
153 }
154 
sim_poll_kbd(void)155 t_stat sim_poll_kbd (void)
156 {
157 int c;
158 
159 if (!kbhit ()) return SCPE_OK;
160 c = _getch ();
161 if ((c & 0177) == '\b') c = 0177;
162 if ((c & 0177) == sim_int_char) return SCPE_STOP;
163 return c | SCPE_KFLAG;
164 }
165 
sim_putchar(int32 c)166 t_stat sim_putchar (int32 c)
167 {
168 _putch (c);
169 return SCPE_OK;
170 }
171 
172 #endif
173 
174 /* BSD UNIX routines */
175 
176 #ifdef BSDTTY
177 #define __TTYROUTINES 0
178 #include <sgtty.h>
179 #include <fcntl.h>
180 
181 struct sgttyb cmdtty,runtty;			/* V6/V7 stty data */
182 struct tchars cmdtchars,runtchars;		/* V7 editing */
183 struct ltchars cmdltchars,runltchars;		/* 4.2 BSD editing */
184 int cmdfl,runfl;				/* TTY flags */
185 
ttinit(void)186 t_stat ttinit (void)
187 {
188 cmdfl = fcntl (0, F_GETFL, 0);			/* get old flags  and status */
189 runfl = cmdfl | FNDELAY;
190 if (ioctl (0, TIOCGETP, &cmdtty) < 0) return SCPE_TTIERR;
191 if (ioctl (0, TIOCGETC, &cmdtchars) < 0) return SCPE_TTIERR;
192 if (ioctl (0, TIOCGLTC, &cmdltchars) < 0) return SCPE_TTIERR;
193 runtty = cmdtty;				/* initial run state */
194 runtty.sg_flags = cmdtty.sg_flags & ~(ECHO|CRMOD) | CBREAK;
195 runtchars.t_intrc = sim_int_char;		/* interrupt */
196 runtchars.t_quitc = 0xFF;			/* no quit */
197 runtchars.t_startc = 0xFF;			/* no host sync */
198 runtchars.t_stopc = 0xFF;
199 runtchars.t_eofc = 0xFF;
200 runtchars.t_brkc = 0xFF;
201 runltchars.t_suspc = 0xFF;			/* no specials of any kind */
202 runltchars.t_dsuspc = 0xFF;
203 runltchars.t_rprntc = 0xFF;
204 runltchars.t_flushc = 0xFF;
205 runltchars.t_werasc = 0xFF;
206 runltchars.t_lnextc = 0xFF;
207 return SCPE_OK;					/* return success */
208 }
209 
ttrunstate(void)210 t_stat ttrunstate (void)
211 {
212 runtchars.t_intrc = sim_int_char;		/* in case changed */
213 fcntl (0, F_SETFL, runfl);			/* non-block mode */
214 if (ioctl (0, TIOCSETP, &runtty) < 0) return SCPE_TTIERR;
215 if (ioctl (0, TIOCSETC, &runtchars) < 0) return SCPE_TTIERR;
216 if (ioctl (0, TIOCSLTC, &runltchars) < 0) return SCPE_TTIERR;
217 return SCPE_OK;
218 }
219 
ttcmdstate(void)220 t_stat ttcmdstate (void)
221 {
222 fcntl (0, F_SETFL, cmdfl);			/* block mode */
223 if (ioctl (0, TIOCSETP, &cmdtty) < 0) return SCPE_TTIERR;
224 if (ioctl (0, TIOCSETC, &cmdtchars) < 0) return SCPE_TTIERR;
225 if (ioctl (0, TIOCSLTC, &cmdltchars) < 0) return SCPE_TTIERR;
226 return SCPE_OK;
227 }
228 
ttclose(void)229 t_stat ttclose (void)
230 {
231 return ttcmdstate ();
232 }
233 
sim_poll_kbd(void)234 t_stat sim_poll_kbd (void)
235 {
236 int status;
237 unsigned char buf[1];
238 
239 status = read (0, buf, 1);
240 if (status != 1) return SCPE_OK;
241 else return (buf[0] | SCPE_KFLAG);
242 }
243 
sim_putchar(int32 out)244 t_stat sim_putchar (int32 out)
245 {
246 char c;
247 
248 c = out;
249 write (1, &c, 1);
250 return SCPE_OK;
251 }
252 #endif
253 
254 /* POSIX UNIX routines */
255 
256 #ifndef __TTYROUTINES
257 #include <unistd.h>
258 #include <termios.h>
259 
260 struct termios cmdtty, runtty;
261 
ttinit(void)262 t_stat ttinit (void)
263 {
264 if (tcgetattr (0, &cmdtty) < 0) return SCPE_TTIERR;	/* get old flags */
265 runtty = cmdtty;
266 runtty.c_lflag = runtty.c_lflag & ~(ECHO | ICANON);	/* no echo or edit */
267 runtty.c_oflag = runtty.c_oflag & ~OPOST;		/* no output edit */
268 runtty.c_iflag = runtty.c_iflag & ~ICRNL;		/* no cr conversion */
269 runtty.c_cc[VINTR] = sim_int_char;			/* interrupt */
270 runtty.c_cc[VQUIT] = 0;					/* no quit */
271 runtty.c_cc[VERASE] = 0;
272 runtty.c_cc[VKILL] = 0;
273 runtty.c_cc[VEOF] = 0;
274 runtty.c_cc[VEOL] = 0;
275 runtty.c_cc[VSTART] = 0;				/* no host sync */
276 runtty.c_cc[VSUSP] = 0;
277 runtty.c_cc[VSTOP] = 0;
278 /* XXX Check if these don't have another name on HP-UX */
279 #ifdef VREPRINT
280 runtty.c_cc[VREPRINT] = 0;				/* no specials */
281 #endif
282 #ifdef VDISCARD
283 runtty.c_cc[VDISCARD] = 0;
284 #endif
285 #ifdef VWERASE
286 runtty.c_cc[VWERASE] = 0;
287 #endif
288 #ifdef VLNEXT
289 runtty.c_cc[VLNEXT] = 0;
290 #endif
291 runtty.c_cc[VMIN] = 0;					/* no waiting */
292 runtty.c_cc[VTIME] = 0;
293 return SCPE_OK;
294 }
295 
ttrunstate(void)296 t_stat ttrunstate (void)
297 {
298 runtty.c_cc[VINTR] = sim_int_char;			/* in case changed */
299 if (tcsetattr (0, TCSAFLUSH, &runtty) < 0) return SCPE_TTIERR;
300 return SCPE_OK;
301 }
302 
ttcmdstate(void)303 t_stat ttcmdstate (void)
304 {
305 if (tcsetattr (0, TCSAFLUSH, &cmdtty) < 0) return SCPE_TTIERR;
306 return SCPE_OK;
307 }
308 
ttclose(void)309 t_stat ttclose (void)
310 {
311 return ttcmdstate ();
312 }
313 
sim_poll_kbd(void)314 t_stat sim_poll_kbd (void)
315 {
316 int status;
317 unsigned char buf[1];
318 
319 status = read (0, buf, 1);
320 if (status != 1) return SCPE_OK;
321 else return (buf[0] | SCPE_KFLAG);
322 }
323 
sim_putchar(int32 out)324 t_stat sim_putchar (int32 out)
325 {
326 char c;
327 
328 c = out;
329 write (1, &c, 1);
330 return SCPE_OK;
331 }
332 #endif
333 
334