/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 43 - (hide annotations)
Mon Oct 8 16:22:43 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 23701 byte(s)
0.4.6
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 42 * $Id: console.c,v 1.26 2007/06/15 18:07:33 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 dpavlin 42 #include <time.h>
74 dpavlin 2
75     #include "console.h"
76     #include "emul.h"
77     #include "machine.h"
78 dpavlin 24 #include "settings.h"
79 dpavlin 2
80    
81     extern char *progname;
82 dpavlin 22 extern int verbose;
83 dpavlin 24 extern struct settings *global_settings;
84 dpavlin 2
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 dpavlin 32 static struct settings *console_settings = NULL;
95 dpavlin 2 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 dpavlin 22 int in_use_for_input;
110 dpavlin 2 int using_xterm;
111     int inputonly;
112 dpavlin 22 int outputonly;
113     int warning_printed;
114 dpavlin 2
115 dpavlin 22 char *machine_name;
116 dpavlin 2 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 dpavlin 32 * console_deinit_main():
137 dpavlin 2 *
138     * Restore host's console settings.
139     */
140 dpavlin 32 void console_deinit_main(void)
141 dpavlin 2 {
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 dpavlin 32 * 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 dpavlin 2 */
160     void console_sigcont(int x)
161     {
162     if (!console_initialized)
163     return;
164    
165 dpavlin 32 /* Make sure that the correct (current) termios setting is active: */
166 dpavlin 2 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 dpavlin 22 * 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 dpavlin 2 */
182     static void start_xterm(int handle)
183     {
184     int filedes[2];
185     int filedesB[2];
186     int res;
187 dpavlin 22 size_t mlen;
188 dpavlin 2 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 dpavlin 42 CHECK_ALLOCATION(a = malloc(sizeof(char *) * 20));
208 dpavlin 2
209     a[0] = getenv("XTERM");
210     if (a[0] == NULL)
211     a[0] = "xterm";
212 dpavlin 6 a[1] = "-geometry";
213     a[2] = "80x25";
214     a[3] = "-title";
215 dpavlin 22 mlen = strlen(console_handles[handle].name) +
216     strlen(console_handles[handle].machine_name) + 30;
217 dpavlin 42 CHECK_ALLOCATION(a[4] = malloc(mlen));
218 dpavlin 22 snprintf(a[4], mlen, "GXemul: %s %s",
219     console_handles[handle].machine_name,
220     console_handles[handle].name);
221 dpavlin 6 a[5] = "-e";
222     a[6] = progname;
223 dpavlin 42 CHECK_ALLOCATION(a[7] = malloc(80));
224 dpavlin 10 snprintf(a[7], 80, "-WW@S%i,%i", filedes[0], filedesB[1]);
225 dpavlin 6 a[8] = NULL;
226 dpavlin 2
227     p = fork();
228     if (p == -1) {
229 dpavlin 22 printf("[ start_xterm(): ERROR while trying to "
230 dpavlin 2 "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 dpavlin 22 printf("[ start_xterm(): ERROR while trying "
239 dpavlin 2 "to do a setsid(): %i ]\n", errno);
240    
241     res = execvp(a[0], a);
242 dpavlin 22 printf("[ start_xterm(): ERROR while trying to "
243 dpavlin 2 "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 dpavlin 22 if (errno == ENOENT)
252     printf("[ Most probably you don't have xterm"
253     " in your PATH. Try again. ]\n");
254 dpavlin 2 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 dpavlin 22 if (!console_handles[handle].in_use_for_input)
319     return 0;
320    
321 dpavlin 2 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 dpavlin 22 if (!console_handles[handle].in_use_for_input &&
403     !console_handles[handle].outputonly)
404     console_change_inputability(handle, 1);
405    
406 dpavlin 2 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 dpavlin 32 char buf[16384];
541 dpavlin 2
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 dpavlin 32 usleep(10000);
587 dpavlin 2 }
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 dpavlin 42 CHECK_ALLOCATION(console_handles =
615     realloc(console_handles, sizeof(
616     struct console_handle) * (n_console_handles + 1)));
617 dpavlin 2 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 dpavlin 22 chp->machine_name = "";
626 dpavlin 42 CHECK_ALLOCATION(chp->name = strdup(name));
627 dpavlin 2
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 dpavlin 22 * 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 dpavlin 2 * 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 dpavlin 22 int console_start_slave(struct machine *machine, char *consolename,
659     int use_for_input)
660 dpavlin 2 {
661 dpavlin 22 struct console_handle *chp;
662 dpavlin 2 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 dpavlin 22 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 dpavlin 2 }
675 dpavlin 32
676 dpavlin 42 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 dpavlin 32
683 dpavlin 42 CHECK_ALLOCATION(chp->name = strdup(consolename));
684 dpavlin 2
685 dpavlin 22 if (allow_slaves)
686     chp->using_xterm = USING_XTERM_BUT_NOT_YET_OPEN;
687 dpavlin 2
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 dpavlin 22 int console_start_slave_inputonly(struct machine *machine, char *consolename,
705     int use_for_input)
706 dpavlin 2 {
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 dpavlin 22 chp->in_use_for_input = use_for_input;
718 dpavlin 42 CHECK_ALLOCATION(chp->machine_name = strdup(machine->name));
719     CHECK_ALLOCATION(chp->name = strdup(consolename));
720 dpavlin 2
721 dpavlin 22 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 dpavlin 2 exit(1);
739     }
740    
741 dpavlin 22 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 dpavlin 2 }
762    
763    
764     /*
765     * console_init_main():
766     *
767 dpavlin 22 * Puts the host's console into single-character (non-canonical) mode.
768 dpavlin 2 */
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 dpavlin 22 * 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 dpavlin 2 * 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 dpavlin 20 * 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 dpavlin 22 * 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 dpavlin 20 */
896 dpavlin 22 int console_warn_if_slaves_are_needed(int init)
897 dpavlin 20 {
898     int i, n = 0;
899 dpavlin 22
900     if (allow_slaves)
901     return 0;
902    
903 dpavlin 20 for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
904     if (console_handles[i].in_use &&
905 dpavlin 22 console_handles[i].in_use_for_input &&
906 dpavlin 20 !console_handles[i].using_xterm)
907     n ++;
908    
909 dpavlin 22 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 dpavlin 20 }
926 dpavlin 22
927     return 0;
928 dpavlin 20 }
929    
930    
931     /*
932 dpavlin 2 * 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 dpavlin 32 console_settings = settings_new();
943    
944 dpavlin 24 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 dpavlin 2 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 dpavlin 22
957     chp->in_use_for_input = 1;
958 dpavlin 2 }
959    
960 dpavlin 32
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