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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26