console.cc Source File

Back to the index.

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

Generated on Tue Aug 25 2020 19:25:06 for GXemul by doxygen 1.8.18