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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26