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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (hide annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 23798 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1632 2007/09/11 21:46:35 debug Exp $
20070616	Implementing the MIPS32/64 revision 2 "ror" instruction.
20070617	Adding a struct for each physpage which keeps track of which
		ranges within that page (base offset, length) that are
		continuously translatable. When running with native code
		generation enabled (-b), a range is added after each read-
		ahead loop.
		Experimenting with using the physical program counter sample
		data (implemented 20070608) together with the "translatable
		range" information, to figure out which physical address ranges
		would be worth translating to native code (if the number of
		samples falling within a range is above a certain threshold).
20070618	Adding automagic building of .index comment files for
		src/file/, src/promemul/, src src/useremul/ as well.
		Adding a "has been translated" bit to the ranges, so that only
		not-yet-translated ranges will be sampled.
20070619	Moving src/cpu.c and src/memory_rw.c into src/cpus/,
		src/device.c into src/devices/, and src/machine.c into
		src/machines/.
		Creating a skeleton cc/ld native backend module; beginning on
		the function which will detect cc command line, etc.
20070620	Continuing on the native code generation infrastructure.
20070621	Moving src/x11.c and src/console.c into a new src/console/
		subdir (for everything that is console or framebuffer related).
		Moving src/symbol*.c into a new src/symbol/, which should
		contain anything that is symbol handling related.
20070624	Making the program counter sampling threshold a "settings
		variable" (sampling_threshold), i.e. it can now be changed
		during runtime.
		Switching the RELEASE notes format from plain text to HTML.
		If the TMPDIR environment variable is set, it is used instead
		of "/tmp" for temporary files.
		Continuing on the cc/ld backend: simple .c code is generated,
		the compiler and linker are called, etc.
		Adding detection of host architecture to the configure script
		(again), and adding icache invalidation support (only
		implemented for Alpha hosts so far).
20070625	Simplifying the program counter sampling mechanism.
20070626	Removing the cc/ld native code generation stuff, program
		counter sampling, etc; it would not have worked well in the
		general case.
20070627	Removing everything related to native code generation.
20070629	Removing the (practically unusable) support for multiple
		emulations. (The single emulation allowed now still supports
		multiple simultaneous machines, as before.)
		Beginning on PCCTWO and M88K interrupts.
20070723	Adding a dummy skeleton for emulation of M32R processors.
20070901	Fixing a warning found by "gcc version 4.3.0 20070817
		(experimental)" on amd64.
20070905	Removing some more traces of the old "multiple emulations"
		code.
		Also looking in /usr/local/include and /usr/local/lib for
		X11 libs, when running configure.
20070909	Minor updates to the guest OS install instructions, in
		preparation for the NetBSD 4.0 release.
20070918	More testing of NetBSD 4.0 RC1.

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

  ViewVC Help
Powered by ViewVC 1.1.26