/[gxemul]/trunk/src/console/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/console.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (show annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 23798 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1632 2007/09/11 21:46:35 debug Exp $
20070616	Implementing the MIPS32/64 revision 2 "ror" instruction.
20070617	Adding a struct for each physpage which keeps track of which
		ranges within that page (base offset, length) that are
		continuously translatable. When running with native code
		generation enabled (-b), a range is added after each read-
		ahead loop.
		Experimenting with using the physical program counter sample
		data (implemented 20070608) together with the "translatable
		range" information, to figure out which physical address ranges
		would be worth translating to native code (if the number of
		samples falling within a range is above a certain threshold).
20070618	Adding automagic building of .index comment files for
		src/file/, src/promemul/, src src/useremul/ as well.
		Adding a "has been translated" bit to the ranges, so that only
		not-yet-translated ranges will be sampled.
20070619	Moving src/cpu.c and src/memory_rw.c into src/cpus/,
		src/device.c into src/devices/, and src/machine.c into
		src/machines/.
		Creating a skeleton cc/ld native backend module; beginning on
		the function which will detect cc command line, etc.
20070620	Continuing on the native code generation infrastructure.
20070621	Moving src/x11.c and src/console.c into a new src/console/
		subdir (for everything that is console or framebuffer related).
		Moving src/symbol*.c into a new src/symbol/, which should
		contain anything that is symbol handling related.
20070624	Making the program counter sampling threshold a "settings
		variable" (sampling_threshold), i.e. it can now be changed
		during runtime.
		Switching the RELEASE notes format from plain text to HTML.
		If the TMPDIR environment variable is set, it is used instead
		of "/tmp" for temporary files.
		Continuing on the cc/ld backend: simple .c code is generated,
		the compiler and linker are called, etc.
		Adding detection of host architecture to the configure script
		(again), and adding icache invalidation support (only
		implemented for Alpha hosts so far).
20070625	Simplifying the program counter sampling mechanism.
20070626	Removing the cc/ld native code generation stuff, program
		counter sampling, etc; it would not have worked well in the
		general case.
20070627	Removing everything related to native code generation.
20070629	Removing the (practically unusable) support for multiple
		emulations. (The single emulation allowed now still supports
		multiple simultaneous machines, as before.)
		Beginning on PCCTWO and M88K interrupts.
20070723	Adding a dummy skeleton for emulation of M32R processors.
20070901	Fixing a warning found by "gcc version 4.3.0 20070817
		(experimental)" on amd64.
20070905	Removing some more traces of the old "multiple emulations"
		code.
		Also looking in /usr/local/include and /usr/local/lib for
		X11 libs, when running configure.
20070909	Minor updates to the guest OS install instructions, in
		preparation for the NetBSD 4.0 release.
20070918	More testing of NetBSD 4.0 RC1.

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

  ViewVC Help
Powered by ViewVC 1.1.26