/[gxemul]/trunk/src/console.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/console.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (13 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 23909 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


1 /*
2 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: console.c,v 1.15 2006/02/18 13:42:38 debug Exp $
29 *
30 * Generic console support functions.
31 *
32 * This module is used by individual device drivers, for example serial
33 * controllers, keyboards, or other devices which need to attach to the
34 * emulator's real stdin/stdout.
35 *
36 * The idea is that several input and output streams (console handles) are
37 * allowed. As long as the number of input streams is <= 1, then everything
38 * can be done in the emulator's default terminal window.
39 *
40 * If the number of inputs is more than 1, it is necessary to open up slave
41 * xterm windows for each input. (Otherwise the behaviour is undefined; i.e.
42 * which of two emulated serial controllers would get keyboard input?)
43 *
44 * (If the -x command line option is NOT used, then slaves are not opened up.
45 * Instead, a warning message is printed, and input is not allowed.)
46 *
47 * Note that console handles that _allow_ input but are not yet used for
48 * output are not counted. This allows a machine to have, say, 2 serial ports
49 * which can be used for both input and output, and it will still be possible
50 * to run in the default terminal window as long as only one of those serial
51 * ports is actually used.
52 *
53 * xterms are opened up "on demand", when output is sent to them.
54 *
55 * The MAIN console handle (fixed as handle nr 0) is the one used by the
56 * default terminal window. A machine which registers a serial controller,
57 * which should be used as the main way of communicating with guest operating
58 * systems running on that machine, should set machine->main_console_handle
59 * to the handle of the correct port on that controller.
60 *
61 *
62 * NOTE: The code in this module is mostly non-reentrant.
63 */
64
65 #include <errno.h>
66 #include <signal.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <termios.h>
71 #include <unistd.h>
72 #include <sys/types.h>
73
74 #include "console.h"
75 #include "emul.h"
76 #include "machine.h"
77 #include "memory.h"
78 #include "misc.h"
79
80
81 extern char *progname;
82 extern int verbose;
83
84
85 static struct termios console_oldtermios;
86 static struct termios console_curtermios;
87
88 /* For 'slave' mode: */
89 static struct termios console_slave_tios;
90 static int console_slave_outputd;
91
92 static int console_initialized = 0;
93 static int console_stdout_pending;
94
95 #define CONSOLE_FIFO_LEN 4096
96
97 /* Mouse coordinates: */
98 static int console_framebuffer_mouse_x; /* absolute x, 0-based */
99 static int console_framebuffer_mouse_y; /* absolute y, 0-based */
100 static int console_framebuffer_mouse_fb_nr; /* fb_number of last
101 framebuffer cursor update */
102
103 static int console_mouse_x; /* absolute x, 0-based */
104 static int console_mouse_y; /* absolute y, 0-based */
105 static int console_mouse_fb_nr; /* framebuffer number of
106 host movement, 0-based */
107 static int console_mouse_buttons; /* left=4, middle=2, right=1 */
108
109 static int allow_slaves = 0;
110
111 struct console_handle {
112 int in_use;
113 int in_use_for_input;
114 int using_xterm;
115 int inputonly;
116 int outputonly;
117 int warning_printed;
118
119 char *machine_name;
120 char *name;
121
122 int w_descriptor;
123 int r_descriptor;
124
125 unsigned char fifo[CONSOLE_FIFO_LEN];
126 int fifo_head;
127 int fifo_tail;
128 };
129
130 #define NOT_USING_XTERM 0
131 #define USING_XTERM_BUT_NOT_YET_OPEN 1
132 #define USING_XTERM 2
133
134 /* A simple array of console_handles */
135 static struct console_handle *console_handles = NULL;
136 static int n_console_handles = 0;
137
138
139 /*
140 * console_deinit():
141 *
142 * Restore host's console settings.
143 */
144 void console_deinit(void)
145 {
146 if (!console_initialized)
147 return;
148
149 tcsetattr(STDIN_FILENO, TCSANOW, &console_oldtermios);
150
151 console_initialized = 0;
152 }
153
154
155 /*
156 * console_sigcont():
157 *
158 * If the user presses CTRL-Z (to stop the emulator process) and then
159 * continues, we have to make sure that the right termios settings are
160 * active. (This should be set as the SIGCONT signal handler in src/emul.c.)
161 */
162 void console_sigcont(int x)
163 {
164 if (!console_initialized)
165 return;
166
167 /* Make sure our 'current' termios setting is active: */
168 tcsetattr(STDIN_FILENO, TCSANOW, &console_curtermios);
169
170 /* Reset the signal handler: */
171 signal(SIGCONT, console_sigcont);
172 }
173
174
175 /*
176 * start_xterm():
177 *
178 * When using X11 (well, when allow_slaves is set), this routine tries to
179 * start up an xterm, with another copy of gxemul inside. The other gxemul
180 * copy is given arguments that will cause it to run console_slave().
181 *
182 * TODO: This is ugly and hardcoded. Clean it up.
183 */
184 static void start_xterm(int handle)
185 {
186 int filedes[2];
187 int filedesB[2];
188 int res;
189 size_t mlen;
190 char **a;
191 pid_t p;
192
193 res = pipe(filedes);
194 if (res) {
195 printf("[ start_xterm(): pipe(): %i ]\n", errno);
196 exit(1);
197 }
198
199 res = pipe(filedesB);
200 if (res) {
201 printf("[ start_xterm(): pipe(): %i ]\n", errno);
202 exit(1);
203 }
204
205 /* printf("filedes = %i,%i\n", filedes[0], filedes[1]); */
206 /* printf("filedesB = %i,%i\n", filedesB[0], filedesB[1]); */
207
208 /* NOTE/warning: Hardcoded max nr of args! */
209 a = malloc(sizeof(char *) * 20);
210 if (a == NULL) {
211 fprintf(stderr, "start_xterm(): out of memory\n");
212 exit(1);
213 }
214
215 a[0] = getenv("XTERM");
216 if (a[0] == NULL)
217 a[0] = "xterm";
218 a[1] = "-geometry";
219 a[2] = "80x25";
220 a[3] = "-title";
221 mlen = strlen(console_handles[handle].name) +
222 strlen(console_handles[handle].machine_name) + 30;
223 a[4] = malloc(mlen);
224 snprintf(a[4], mlen, "GXemul: %s %s",
225 console_handles[handle].machine_name,
226 console_handles[handle].name);
227 a[5] = "-e";
228 a[6] = progname;
229 a[7] = malloc(80);
230 snprintf(a[7], 80, "-WW@S%i,%i", filedes[0], filedesB[1]);
231 a[8] = NULL;
232
233 p = fork();
234 if (p == -1) {
235 printf("[ start_xterm(): ERROR while trying to "
236 "fork(): %i ]\n", errno);
237 exit(1);
238 } else if (p == 0) {
239 close(filedes[1]);
240 close(filedesB[0]);
241
242 p = setsid();
243 if (p < 0)
244 printf("[ start_xterm(): ERROR while trying "
245 "to do a setsid(): %i ]\n", errno);
246
247 res = execvp(a[0], a);
248 printf("[ start_xterm(): ERROR while trying to "
249 "execvp(\"");
250 while (a[0] != NULL) {
251 printf("%s", a[0]);
252 if (a[1] != NULL)
253 printf(" ");
254 a++;
255 }
256 printf("\"): %i ]\n", errno);
257 if (errno == ENOENT)
258 printf("[ Most probably you don't have xterm"
259 " in your PATH. Try again. ]\n");
260 exit(1);
261 }
262
263 /* TODO: free a and a[*] */
264
265 close(filedes[0]);
266 close(filedesB[1]);
267
268 console_handles[handle].using_xterm = USING_XTERM;
269
270 /*
271 * write to filedes[1], read from filedesB[0]
272 */
273
274 console_handles[handle].w_descriptor = filedes[1];
275 console_handles[handle].r_descriptor = filedesB[0];
276 }
277
278
279 /*
280 * d_avail():
281 *
282 * Returns 1 if anything is available on a descriptor.
283 */
284 static int d_avail(int d)
285 {
286 fd_set rfds;
287 struct timeval tv;
288
289 FD_ZERO(&rfds);
290 FD_SET(d, &rfds);
291 tv.tv_sec = 0;
292 tv.tv_usec = 0;
293 return select(d+1, &rfds, NULL, NULL, &tv);
294 }
295
296
297 /*
298 * console_makeavail():
299 *
300 * Put a character in the queue, so that it will be avaiable,
301 * by inserting it into the char fifo.
302 */
303 void console_makeavail(int handle, char ch)
304 {
305 console_handles[handle].fifo[
306 console_handles[handle].fifo_head] = ch;
307 console_handles[handle].fifo_head = (
308 console_handles[handle].fifo_head + 1) % CONSOLE_FIFO_LEN;
309
310 if (console_handles[handle].fifo_head ==
311 console_handles[handle].fifo_tail)
312 fatal("[ WARNING: console fifo overrun, handle %i ]\n", handle);
313 }
314
315
316 /*
317 * console_stdin_avail():
318 *
319 * Returns 1 if a char is available from a handle's read descriptor,
320 * 0 otherwise.
321 */
322 static int console_stdin_avail(int handle)
323 {
324 if (!console_handles[handle].in_use_for_input)
325 return 0;
326
327 if (!allow_slaves)
328 return d_avail(STDIN_FILENO);
329
330 if (console_handles[handle].using_xterm ==
331 USING_XTERM_BUT_NOT_YET_OPEN)
332 return 0;
333
334 return d_avail(console_handles[handle].r_descriptor);
335 }
336
337
338 /*
339 * console_charavail():
340 *
341 * Returns 1 if a char is available in the fifo, 0 otherwise.
342 */
343 int console_charavail(int handle)
344 {
345 while (console_stdin_avail(handle)) {
346 unsigned char ch[100]; /* = getchar(); */
347 ssize_t len;
348 int i, d;
349
350 if (!allow_slaves)
351 d = STDIN_FILENO;
352 else
353 d = console_handles[handle].r_descriptor;
354
355 len = read(d, ch, sizeof(ch));
356
357 for (i=0; i<len; i++) {
358 /* printf("[ %i: %i ]\n", i, ch[i]); */
359
360 if (!allow_slaves) {
361 /* Ugly hack: convert ctrl-b into ctrl-c.
362 (TODO: fix) */
363 if (ch[i] == 2)
364 ch[i] = 3;
365 }
366
367 console_makeavail(handle, ch[i]);
368 }
369 }
370
371 if (console_handles[handle].fifo_head ==
372 console_handles[handle].fifo_tail)
373 return 0;
374
375 return 1;
376 }
377
378
379 /*
380 * console_readchar():
381 *
382 * Returns 0..255 if a char was available, -1 otherwise.
383 */
384 int console_readchar(int handle)
385 {
386 int ch;
387
388 if (!console_charavail(handle))
389 return -1;
390
391 ch = console_handles[handle].fifo[console_handles[handle].fifo_tail];
392 console_handles[handle].fifo_tail ++;
393 console_handles[handle].fifo_tail %= CONSOLE_FIFO_LEN;
394
395 return ch;
396 }
397
398
399 /*
400 * console_putchar():
401 *
402 * Prints a char to stdout, and sets the console_stdout_pending flag.
403 */
404 void console_putchar(int handle, int ch)
405 {
406 char buf[1];
407
408 if (!console_handles[handle].in_use_for_input &&
409 !console_handles[handle].outputonly)
410 console_change_inputability(handle, 1);
411
412 if (!allow_slaves) {
413 /* stdout: */
414 putchar(ch);
415
416 /* Assume flushes by OS or libc on newlines: */
417 if (ch == '\n')
418 console_stdout_pending = 0;
419 else
420 console_stdout_pending = 1;
421
422 return;
423 }
424
425 if (!console_handles[handle].in_use) {
426 printf("[ console_putchar(): handle %i not in"
427 " use! ]\n", handle);
428 return;
429 }
430
431 if (console_handles[handle].using_xterm ==
432 USING_XTERM_BUT_NOT_YET_OPEN)
433 start_xterm(handle);
434
435 buf[0] = ch;
436 write(console_handles[handle].w_descriptor, buf, 1);
437 }
438
439
440 /*
441 * console_flush():
442 *
443 * Flushes stdout, if necessary, and resets console_stdout_pending to zero.
444 */
445 void console_flush(void)
446 {
447 if (console_stdout_pending)
448 fflush(stdout);
449
450 console_stdout_pending = 0;
451 }
452
453
454 /*
455 * console_mouse_coordinates():
456 *
457 * Sets mouse coordinates. Called by for example an X11 event handler.
458 * x and y are absolute coordinates, fb_nr is where the mouse movement
459 * took place.
460 */
461 void console_mouse_coordinates(int x, int y, int fb_nr)
462 {
463 /* TODO: fb_nr isn't used yet. */
464
465 console_mouse_x = x;
466 console_mouse_y = y;
467 console_mouse_fb_nr = fb_nr;
468 }
469
470
471 /*
472 * console_mouse_button():
473 *
474 * Sets a mouse button to be pressed or released. Called by for example an
475 * X11 event handler. button is 1 (left), 2 (middle), or 3 (right), and
476 * pressed = 1 for pressed, 0 for not pressed.
477 */
478 void console_mouse_button(int button, int pressed)
479 {
480 int mask = 1 << (3-button);
481
482 if (pressed)
483 console_mouse_buttons |= mask;
484 else
485 console_mouse_buttons &= ~mask;
486 }
487
488
489 /*
490 * console_get_framebuffer_mouse():
491 *
492 * TODO: Comment
493 */
494 void console_get_framebuffer_mouse(int *x, int *y, int *fb_nr)
495 {
496 *x = console_framebuffer_mouse_x;
497 *y = console_framebuffer_mouse_y;
498 *fb_nr = console_framebuffer_mouse_fb_nr;
499 }
500
501
502 /*
503 * console_set_framebuffer_mouse():
504 *
505 * A framebuffer device calls this function when it sets the
506 * position of a cursor (ie a mouse cursor).
507 */
508 void console_set_framebuffer_mouse(int x, int y, int fb_nr)
509 {
510 console_framebuffer_mouse_x = x;
511 console_framebuffer_mouse_y = y;
512 console_framebuffer_mouse_fb_nr = fb_nr;
513 }
514
515
516 /*
517 * console_getmouse():
518 *
519 * Puts current mouse data into the variables pointed to by
520 * the arguments.
521 */
522 void console_getmouse(int *x, int *y, int *buttons, int *fb_nr)
523 {
524 *x = console_mouse_x;
525 *y = console_mouse_y;
526 *buttons = console_mouse_buttons;
527 *fb_nr = console_mouse_fb_nr;
528 }
529
530
531 /*
532 * console_slave_sigint():
533 */
534 static void console_slave_sigint(int x)
535 {
536 char buf[1];
537
538 /* Send a ctrl-c: */
539 buf[0] = 3;
540 write(console_slave_outputd, buf, sizeof(buf));
541
542 /* Reset the signal handler: */
543 signal(SIGINT, console_slave_sigint);
544 }
545
546
547 /*
548 * console_slave_sigcont():
549 *
550 * See comment for console_sigcont. This is for used by console_slave().
551 */
552 static void console_slave_sigcont(int x)
553 {
554 /* Make sure our 'current' termios setting is active: */
555 tcsetattr(STDIN_FILENO, TCSANOW, &console_slave_tios);
556
557 /* Reset the signal handler: */
558 signal(SIGCONT, console_slave_sigcont);
559 }
560
561
562 /*
563 * console_slave():
564 *
565 * This function is used when running with X11, and gxemul opens up
566 * separate xterms for each emulated terminal or serial port.
567 */
568 void console_slave(char *arg)
569 {
570 int inputd;
571 int len;
572 char *p;
573 char buf[400];
574
575 /* arg = '3,6' or similar, input and output descriptors */
576 /* printf("console_slave(): arg = '%s'\n", arg); */
577
578 inputd = atoi(arg);
579 p = strchr(arg, ',');
580 if (p == NULL) {
581 printf("console_slave(): bad arg '%s'\n", arg);
582 sleep(5);
583 exit(1);
584 }
585 console_slave_outputd = atoi(p+1);
586
587 /* Set the terminal to raw mode: */
588 tcgetattr(STDIN_FILENO, &console_slave_tios);
589
590 console_slave_tios.c_lflag &= ~ICANON;
591 console_slave_tios.c_cc[VTIME] = 0;
592 console_slave_tios.c_cc[VMIN] = 1;
593 console_slave_tios.c_lflag &= ~ECHO;
594 console_slave_tios.c_iflag &= ~ICRNL;
595 tcsetattr(STDIN_FILENO, TCSANOW, &console_slave_tios);
596
597 signal(SIGINT, console_slave_sigint);
598 signal(SIGCONT, console_slave_sigcont);
599
600 for (;;) {
601 /* TODO: select() on both inputd and stdin */
602
603 if (d_avail(inputd)) {
604 len = read(inputd, buf, sizeof(buf) - 1);
605 if (len < 1)
606 exit(0);
607 buf[len] = '\0';
608 printf("%s", buf);
609 fflush(stdout);
610 }
611
612 if (d_avail(STDIN_FILENO)) {
613 len = read(STDIN_FILENO, buf, sizeof(buf));
614 if (len < 1)
615 exit(0);
616 write(console_slave_outputd, buf, len);
617 }
618
619 usleep(100);
620 }
621 }
622
623
624 /*
625 * console_new_handle():
626 *
627 * Allocates a new console_handle struct, and returns a pointer to it.
628 *
629 * For internal use.
630 */
631 static struct console_handle *console_new_handle(char *name, int *handlep)
632 {
633 struct console_handle *chp;
634 int i, n, found_free = -1;
635
636 /* Reuse an old slot, if possible: */
637 n = n_console_handles;
638 for (i=0; i<n; i++)
639 if (!console_handles[i].in_use) {
640 found_free = i;
641 break;
642 }
643
644 if (found_free == -1) {
645 /* Let's realloc console_handles[], to make room
646 for the new one: */
647 console_handles = realloc(console_handles, sizeof(
648 struct console_handle) * (n_console_handles + 1));
649 if (console_handles == NULL) {
650 printf("console_new_handle(): out of memory\n");
651 exit(1);
652 }
653 found_free = n_console_handles;
654 n_console_handles ++;
655 }
656
657 chp = &console_handles[found_free];
658 memset(chp, 0, sizeof(struct console_handle));
659
660 chp->in_use = 1;
661 chp->machine_name = "";
662 chp->name = strdup(name);
663 if (chp->name == NULL) {
664 printf("console_new_handle(): out of memory\n");
665 exit(1);
666 }
667
668 *handlep = found_free;
669 return chp;
670 }
671
672
673 /*
674 * console_start_slave():
675 *
676 * When using X11:
677 *
678 * This routine tries to start up an xterm, with another copy of gxemul
679 * inside. The other gxemul copy is given arguments that will cause it
680 * to run console_slave().
681 *
682 * When not using X11: Things will seem to work the same way without X11,
683 * but no xterm will actually be started.
684 *
685 * consolename should be something like "serial 0".
686 *
687 * If use_for_input is 1, input is allowed right from the start. (This
688 * can be upgraded later from 0 to 1 using the console_change_inputability()
689 * function.)
690 *
691 * If use_for_input is CONSOLE_OUTPUT_ONLY, then this is an output-only stream.
692 *
693 * On success, an integer >= 0 is returned. This can then be used as a
694 * 'handle' when writing to or reading from an emulated console.
695 *
696 * On failure, -1 is returned.
697 */
698 int console_start_slave(struct machine *machine, char *consolename,
699 int use_for_input)
700 {
701 struct console_handle *chp;
702 int handle;
703
704 if (machine == NULL || consolename == NULL) {
705 printf("console_start_slave(): NULL ptr\n");
706 exit(1);
707 }
708
709 chp = console_new_handle(consolename, &handle);
710 chp->in_use_for_input = use_for_input;
711 if (use_for_input == CONSOLE_OUTPUT_ONLY) {
712 chp->outputonly = 1;
713 chp->in_use_for_input = 0;
714 }
715 chp->machine_name = strdup(machine->machine_name);
716 chp->name = strdup(consolename);
717
718 if (allow_slaves)
719 chp->using_xterm = USING_XTERM_BUT_NOT_YET_OPEN;
720
721 return handle;
722 }
723
724
725 /*
726 * console_start_slave_inputonly():
727 *
728 * Similar to console_start_slave(), but doesn't open an xterm. This is
729 * useful for devices such as keyboard controllers, that need to have an
730 * input queue, but no xterm window associated with it.
731 *
732 * On success, an integer >= 0 is returned. This can then be used as a
733 * 'handle' when writing to or reading from an emulated console.
734 *
735 * On failure, -1 is returned.
736 */
737 int console_start_slave_inputonly(struct machine *machine, char *consolename,
738 int use_for_input)
739 {
740 struct console_handle *chp;
741 int handle;
742
743 if (machine == NULL || consolename == NULL) {
744 printf("console_start_slave(): NULL ptr\n");
745 exit(1);
746 }
747
748 chp = console_new_handle(consolename, &handle);
749 chp->inputonly = 1;
750 chp->in_use_for_input = use_for_input;
751 chp->machine_name = strdup(machine->name);
752 chp->name = strdup(consolename);
753
754 return handle;
755 }
756
757
758 /*
759 * console_change_inputability():
760 *
761 * Sets whether or not a console handle can be used for input. Return value
762 * is 1 if the change took place, 0 otherwise.
763 */
764 int console_change_inputability(int handle, int inputability)
765 {
766 int old;
767
768 if (handle < 0 || handle >= n_console_handles) {
769 fatal("console_change_inputability(): bad handle %i\n",
770 handle);
771 exit(1);
772 }
773
774 old = console_handles[handle].in_use_for_input;
775 console_handles[handle].in_use_for_input = inputability;
776
777 if (inputability != 0) {
778 if (console_warn_if_slaves_are_needed(0)) {
779 console_handles[handle].in_use_for_input = old;
780 if (!console_handles[handle].warning_printed) {
781 fatal("%%\n%% WARNING! Input to console ha"
782 "ndle \"%s\" wasn't enabled,\n%% because "
783 "it", console_handles[handle].name);
784 fatal(" would interfere with other inputs,\n"
785 "%% and you did not use the -x command "
786 "line option!\n%%\n");
787 }
788 console_handles[handle].warning_printed = 1;
789 return 0;
790 }
791 }
792
793 return 1;
794 }
795
796
797 /*
798 * console_init_main():
799 *
800 * Puts the host's console into single-character (non-canonical) mode.
801 */
802 void console_init_main(struct emul *emul)
803 {
804 int i, tra;
805
806 if (console_initialized)
807 return;
808
809 tcgetattr(STDIN_FILENO, &console_oldtermios);
810 memcpy(&console_curtermios, &console_oldtermios,
811 sizeof (struct termios));
812
813 console_curtermios.c_lflag &= ~ICANON;
814 console_curtermios.c_cc[VTIME] = 0;
815 console_curtermios.c_cc[VMIN] = 1;
816
817 console_curtermios.c_lflag &= ~ECHO;
818
819 /*
820 * Most guest OSes seem to work ok without ~ICRNL, but Linux on
821 * DECstation requires it to be usable. Unfortunately, clearing
822 * out ICRNL makes tracing with '-t ... |more' akward, as you
823 * might need to use CTRL-J instead of the enter key. Hence,
824 * this bit is only cleared if we're not tracing:
825 */
826 tra = 0;
827 for (i=0; i<emul->n_machines; i++)
828 if (emul->machines[i]->show_trace_tree ||
829 emul->machines[i]->instruction_trace ||
830 emul->machines[i]->register_dump)
831 tra = 1;
832 if (!tra)
833 console_curtermios.c_iflag &= ~ICRNL;
834
835 tcsetattr(STDIN_FILENO, TCSANOW, &console_curtermios);
836
837 console_stdout_pending = 1;
838 console_handles[MAIN_CONSOLE].fifo_head = 0;
839 console_handles[MAIN_CONSOLE].fifo_tail = 0;
840
841 console_mouse_x = 0;
842 console_mouse_y = 0;
843 console_mouse_buttons = 0;
844
845 console_initialized = 1;
846 }
847
848
849 /*
850 * console_debug_dump():
851 *
852 * Dump debug info, if verbose >= 2.
853 */
854 void console_debug_dump(struct machine *machine)
855 {
856 int i, iadd = DEBUG_INDENTATION, listed_main = 0;
857
858 if (verbose < 2)
859 return;
860
861 debug("console slaves (xterms): %s\n", allow_slaves?
862 "yes" : "no");
863
864 debug("console handles:\n");
865 debug_indentation(iadd);
866
867 for (i=0; i<n_console_handles; i++) {
868 if (!console_handles[i].in_use)
869 continue;
870 debug("%i: \"%s\"", i, console_handles[i].name);
871 if (console_handles[i].using_xterm)
872 debug(" [xterm]");
873 if (console_handles[i].inputonly)
874 debug(" [inputonly]");
875 if (console_handles[i].outputonly)
876 debug(" [outputonly]");
877 if (i == machine->main_console_handle) {
878 debug(" [MAIN CONSOLE]");
879 listed_main = 1;
880 }
881 debug("\n");
882 }
883
884 debug_indentation(-iadd);
885
886 if (!listed_main)
887 fatal("WARNING! no main console handle?\n");
888 }
889
890
891 /*
892 * console_allow_slaves():
893 *
894 * This function tells the console subsystem whether or not to open up
895 * slave xterms for each emulated serial controller.
896 */
897 void console_allow_slaves(int allow)
898 {
899 allow_slaves = allow;
900 }
901
902
903 /*
904 * console_are_slaves_allowed():
905 *
906 * Returns the value of allow_slaves.
907 */
908 int console_are_slaves_allowed(void)
909 {
910 return allow_slaves;
911 }
912
913
914 /*
915 * console_warn_if_slaves_are_needed():
916 *
917 * Prints an error (during startup of the emulator) if slave xterms are needed
918 * (i.e. there is more than one console handle in use which is used for
919 * INPUT), but they are not currently allowed.
920 *
921 * This function should be called during startup (with init = 1), and every
922 * time a console handle changes/upgrades its in_use_for_input from 0 to 1.
923 *
924 * If init is non-zero, this function doesn't return if there was a warning.
925 *
926 * If init is zero, no warning is printed. 1 is returned if there were more
927 * than one input, 0 otherwise.
928 */
929 int console_warn_if_slaves_are_needed(int init)
930 {
931 int i, n = 0;
932
933 if (allow_slaves)
934 return 0;
935
936 for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
937 if (console_handles[i].in_use &&
938 console_handles[i].in_use_for_input &&
939 !console_handles[i].using_xterm)
940 n ++;
941
942 if (n > 1) {
943 if (init) {
944 fatal("#\n# ERROR! More than one console input is "
945 "in use,\n# but xterm slaves are not enabled.\n"
946 "#\n");
947 fatal("# Use -x to enable slave xterms.)\n#\n");
948 for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
949 if (console_handles[i].in_use &&
950 console_handles[i].in_use_for_input &&
951 !console_handles[i].using_xterm)
952 fatal("# console handle %i: '%s'\n",
953 i, console_handles[i].name);
954 fatal("#\n");
955 exit(1);
956 }
957 return 1;
958 }
959
960 return 0;
961 }
962
963
964 /*
965 * console_init():
966 *
967 * This function should be called before any other console_*() function
968 * is used.
969 */
970 void console_init(void)
971 {
972 int handle;
973 struct console_handle *chp;
974
975 chp = console_new_handle("MAIN", &handle);
976 if (handle != MAIN_CONSOLE) {
977 printf("console_init(): fatal error: could not create"
978 " console 0: handle = %i\n", handle);
979 exit(1);
980 }
981
982 chp->in_use_for_input = 1;
983 }
984

  ViewVC Help
Powered by ViewVC 1.1.26