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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 22 - (hide annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 23909 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26