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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 43 - (show annotations)
Mon Oct 8 16:22:43 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 23701 byte(s)
0.4.6
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.26 2007/06/15 18:07:33 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 CHECK_ALLOCATION(chp->machine_name = strdup(machine->name));
719 CHECK_ALLOCATION(chp->name = strdup(consolename));
720
721 return handle;
722 }
723
724
725 /*
726 * console_change_inputability():
727 *
728 * Sets whether or not a console handle can be used for input. Return value
729 * is 1 if the change took place, 0 otherwise.
730 */
731 int console_change_inputability(int handle, int inputability)
732 {
733 int old;
734
735 if (handle < 0 || handle >= n_console_handles) {
736 fatal("console_change_inputability(): bad handle %i\n",
737 handle);
738 exit(1);
739 }
740
741 old = console_handles[handle].in_use_for_input;
742 console_handles[handle].in_use_for_input = inputability;
743
744 if (inputability != 0) {
745 if (console_warn_if_slaves_are_needed(0)) {
746 console_handles[handle].in_use_for_input = old;
747 if (!console_handles[handle].warning_printed) {
748 fatal("%%\n%% WARNING! Input to console ha"
749 "ndle \"%s\" wasn't enabled,\n%% because "
750 "it", console_handles[handle].name);
751 fatal(" would interfere with other inputs,\n"
752 "%% and you did not use the -x command "
753 "line option!\n%%\n");
754 }
755 console_handles[handle].warning_printed = 1;
756 return 0;
757 }
758 }
759
760 return 1;
761 }
762
763
764 /*
765 * console_init_main():
766 *
767 * Puts the host's console into single-character (non-canonical) mode.
768 */
769 void console_init_main(struct emul *emul)
770 {
771 int i, tra;
772
773 if (console_initialized)
774 return;
775
776 tcgetattr(STDIN_FILENO, &console_oldtermios);
777 memcpy(&console_curtermios, &console_oldtermios,
778 sizeof (struct termios));
779
780 console_curtermios.c_lflag &= ~ICANON;
781 console_curtermios.c_cc[VTIME] = 0;
782 console_curtermios.c_cc[VMIN] = 1;
783
784 console_curtermios.c_lflag &= ~ECHO;
785
786 /*
787 * Most guest OSes seem to work ok without ~ICRNL, but Linux on
788 * DECstation requires it to be usable. Unfortunately, clearing
789 * out ICRNL makes tracing with '-t ... |more' akward, as you
790 * might need to use CTRL-J instead of the enter key. Hence,
791 * this bit is only cleared if we're not tracing:
792 */
793 tra = 0;
794 for (i=0; i<emul->n_machines; i++)
795 if (emul->machines[i]->show_trace_tree ||
796 emul->machines[i]->instruction_trace ||
797 emul->machines[i]->register_dump)
798 tra = 1;
799 if (!tra)
800 console_curtermios.c_iflag &= ~ICRNL;
801
802 tcsetattr(STDIN_FILENO, TCSANOW, &console_curtermios);
803
804 console_stdout_pending = 1;
805 console_handles[MAIN_CONSOLE].fifo_head = 0;
806 console_handles[MAIN_CONSOLE].fifo_tail = 0;
807
808 console_mouse_x = 0;
809 console_mouse_y = 0;
810 console_mouse_buttons = 0;
811
812 console_initialized = 1;
813 }
814
815
816 /*
817 * console_debug_dump():
818 *
819 * Dump debug info, if verbose >= 2.
820 */
821 void console_debug_dump(struct machine *machine)
822 {
823 int i, iadd = DEBUG_INDENTATION, listed_main = 0;
824
825 if (verbose < 2)
826 return;
827
828 debug("console slaves (xterms): %s\n", allow_slaves?
829 "yes" : "no");
830
831 debug("console handles:\n");
832 debug_indentation(iadd);
833
834 for (i=0; i<n_console_handles; i++) {
835 if (!console_handles[i].in_use)
836 continue;
837 debug("%i: \"%s\"", i, console_handles[i].name);
838 if (console_handles[i].using_xterm)
839 debug(" [xterm]");
840 if (console_handles[i].inputonly)
841 debug(" [inputonly]");
842 if (console_handles[i].outputonly)
843 debug(" [outputonly]");
844 if (i == machine->main_console_handle) {
845 debug(" [MAIN CONSOLE]");
846 listed_main = 1;
847 }
848 debug("\n");
849 }
850
851 debug_indentation(-iadd);
852
853 if (!listed_main)
854 fatal("WARNING! no main console handle?\n");
855 }
856
857
858 /*
859 * console_allow_slaves():
860 *
861 * This function tells the console subsystem whether or not to open up
862 * slave xterms for each emulated serial controller.
863 */
864 void console_allow_slaves(int allow)
865 {
866 allow_slaves = allow;
867 }
868
869
870 /*
871 * console_are_slaves_allowed():
872 *
873 * Returns the value of allow_slaves.
874 */
875 int console_are_slaves_allowed(void)
876 {
877 return allow_slaves;
878 }
879
880
881 /*
882 * console_warn_if_slaves_are_needed():
883 *
884 * Prints an error (during startup of the emulator) if slave xterms are needed
885 * (i.e. there is more than one console handle in use which is used for
886 * INPUT), but they are not currently allowed.
887 *
888 * This function should be called during startup (with init = 1), and every
889 * time a console handle changes/upgrades its in_use_for_input from 0 to 1.
890 *
891 * If init is non-zero, this function doesn't return if there was a warning.
892 *
893 * If init is zero, no warning is printed. 1 is returned if there were more
894 * than one input, 0 otherwise.
895 */
896 int console_warn_if_slaves_are_needed(int init)
897 {
898 int i, n = 0;
899
900 if (allow_slaves)
901 return 0;
902
903 for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
904 if (console_handles[i].in_use &&
905 console_handles[i].in_use_for_input &&
906 !console_handles[i].using_xterm)
907 n ++;
908
909 if (n > 1) {
910 if (init) {
911 fatal("#\n# ERROR! More than one console input is "
912 "in use,\n# but xterm slaves are not enabled.\n"
913 "#\n");
914 fatal("# Use -x to enable slave xterms.)\n#\n");
915 for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
916 if (console_handles[i].in_use &&
917 console_handles[i].in_use_for_input &&
918 !console_handles[i].using_xterm)
919 fatal("# console handle %i: '%s'\n",
920 i, console_handles[i].name);
921 fatal("#\n");
922 exit(1);
923 }
924 return 1;
925 }
926
927 return 0;
928 }
929
930
931 /*
932 * console_init():
933 *
934 * This function should be called before any other console_*() function
935 * is used.
936 */
937 void console_init(void)
938 {
939 int handle;
940 struct console_handle *chp;
941
942 console_settings = settings_new();
943
944 settings_add(global_settings, "console", 1,
945 SETTINGS_TYPE_SUBSETTINGS, 0, console_settings);
946
947 settings_add(console_settings, "allow_slaves", 0,
948 SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *)&allow_slaves);
949
950 chp = console_new_handle("MAIN", &handle);
951 if (handle != MAIN_CONSOLE) {
952 printf("console_init(): fatal error: could not create"
953 " console 0: handle = %i\n", handle);
954 exit(1);
955 }
956
957 chp->in_use_for_input = 1;
958 }
959
960
961 /*
962 * console_deinit():
963 *
964 * Unregister settings registered by console_init().
965 */
966 void console_deinit(void)
967 {
968 settings_remove(console_settings, "allow_slaves");
969 settings_remove(global_settings, "console");
970 }
971

  ViewVC Help
Powered by ViewVC 1.1.26