/[gxemul]/upstream/0.4.5/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

Annotation of /upstream/0.4.5/src/console.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 39 - (hide annotations)
Mon Oct 8 16:22:02 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 23797 byte(s)
0.4.5
1 dpavlin 2 /*
2 dpavlin 34 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 dpavlin 2 *
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 dpavlin 34 * $Id: console.c,v 1.22 2006/12/30 13:30:51 debug Exp $
29 dpavlin 2 *
30     * Generic console support functions.
31     *
32 dpavlin 22 * 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 dpavlin 2 *
36 dpavlin 22 * 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 dpavlin 2 */
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 dpavlin 24 #include "settings.h"
80 dpavlin 2
81    
82     extern char *progname;
83 dpavlin 22 extern int verbose;
84 dpavlin 24 extern struct settings *global_settings;
85 dpavlin 2
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 dpavlin 32 static struct settings *console_settings = NULL;
96 dpavlin 2 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 dpavlin 22 int in_use_for_input;
111 dpavlin 2 int using_xterm;
112     int inputonly;
113 dpavlin 22 int outputonly;
114     int warning_printed;
115 dpavlin 2
116 dpavlin 22 char *machine_name;
117 dpavlin 2 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 dpavlin 32 * console_deinit_main():
138 dpavlin 2 *
139     * Restore host's console settings.
140     */
141 dpavlin 32 void console_deinit_main(void)
142 dpavlin 2 {
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 dpavlin 32 * 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 dpavlin 2 */
161     void console_sigcont(int x)
162     {
163     if (!console_initialized)
164     return;
165    
166 dpavlin 32 /* Make sure that the correct (current) termios setting is active: */
167 dpavlin 2 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 dpavlin 22 * 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 dpavlin 2 */
183     static void start_xterm(int handle)
184     {
185     int filedes[2];
186     int filedesB[2];
187     int res;
188 dpavlin 22 size_t mlen;
189 dpavlin 2 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 dpavlin 22 fprintf(stderr, "start_xterm(): out of memory\n");
211 dpavlin 2 exit(1);
212     }
213    
214     a[0] = getenv("XTERM");
215     if (a[0] == NULL)
216     a[0] = "xterm";
217 dpavlin 6 a[1] = "-geometry";
218     a[2] = "80x25";
219     a[3] = "-title";
220 dpavlin 22 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 dpavlin 6 a[5] = "-e";
227     a[6] = progname;
228 dpavlin 10 a[7] = malloc(80);
229     snprintf(a[7], 80, "-WW@S%i,%i", filedes[0], filedesB[1]);
230 dpavlin 6 a[8] = NULL;
231 dpavlin 2
232     p = fork();
233     if (p == -1) {
234 dpavlin 22 printf("[ start_xterm(): ERROR while trying to "
235 dpavlin 2 "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 dpavlin 22 printf("[ start_xterm(): ERROR while trying "
244 dpavlin 2 "to do a setsid(): %i ]\n", errno);
245    
246     res = execvp(a[0], a);
247 dpavlin 22 printf("[ start_xterm(): ERROR while trying to "
248 dpavlin 2 "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 dpavlin 22 if (errno == ENOENT)
257     printf("[ Most probably you don't have xterm"
258     " in your PATH. Try again. ]\n");
259 dpavlin 2 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 dpavlin 22 if (!console_handles[handle].in_use_for_input)
324     return 0;
325    
326 dpavlin 2 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 dpavlin 22 if (!console_handles[handle].in_use_for_input &&
408     !console_handles[handle].outputonly)
409     console_change_inputability(handle, 1);
410    
411 dpavlin 2 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 dpavlin 32 char buf[16384];
546 dpavlin 2
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 dpavlin 32 usleep(10000);
592 dpavlin 2 }
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 dpavlin 22 chp->machine_name = "";
634 dpavlin 2 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 dpavlin 22 * 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 dpavlin 2 * 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 dpavlin 22 int console_start_slave(struct machine *machine, char *consolename,
671     int use_for_input)
672 dpavlin 2 {
673 dpavlin 22 struct console_handle *chp;
674 dpavlin 2 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 dpavlin 22 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 dpavlin 2 }
687 dpavlin 32
688     if (machine->machine_name != NULL)
689     chp->machine_name = strdup(machine->machine_name);
690     else
691     chp->machine_name = strdup("");
692    
693 dpavlin 22 chp->name = strdup(consolename);
694 dpavlin 2
695 dpavlin 22 if (allow_slaves)
696     chp->using_xterm = USING_XTERM_BUT_NOT_YET_OPEN;
697 dpavlin 2
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 dpavlin 22 int console_start_slave_inputonly(struct machine *machine, char *consolename,
715     int use_for_input)
716 dpavlin 2 {
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 dpavlin 22 chp->in_use_for_input = use_for_input;
728     chp->machine_name = strdup(machine->name);
729     chp->name = strdup(consolename);
730 dpavlin 2
731 dpavlin 22 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 dpavlin 2 exit(1);
749     }
750    
751 dpavlin 22 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 dpavlin 2 }
772    
773    
774     /*
775     * console_init_main():
776     *
777 dpavlin 22 * Puts the host's console into single-character (non-canonical) mode.
778 dpavlin 2 */
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 dpavlin 22 * 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 dpavlin 2 * 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 dpavlin 20 * 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 dpavlin 22 * 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 dpavlin 20 */
906 dpavlin 22 int console_warn_if_slaves_are_needed(int init)
907 dpavlin 20 {
908     int i, n = 0;
909 dpavlin 22
910     if (allow_slaves)
911     return 0;
912    
913 dpavlin 20 for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
914     if (console_handles[i].in_use &&
915 dpavlin 22 console_handles[i].in_use_for_input &&
916 dpavlin 20 !console_handles[i].using_xterm)
917     n ++;
918    
919 dpavlin 22 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 dpavlin 20 }
936 dpavlin 22
937     return 0;
938 dpavlin 20 }
939    
940    
941     /*
942 dpavlin 2 * 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 dpavlin 32 console_settings = settings_new();
953    
954 dpavlin 24 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 dpavlin 2 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 dpavlin 22
967     chp->in_use_for_input = 1;
968 dpavlin 2 }
969    
970 dpavlin 32
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