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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26