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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26