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

Diff of /trunk/src/console.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 10 by dpavlin, Mon Oct 8 16:18:27 2007 UTC revision 34 by dpavlin, Mon Oct 8 16:21:17 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2007  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: console.c,v 1.9 2005/06/26 11:36:27 debug Exp $   *  $Id: console.c,v 1.22 2006/12/30 13:30:51 debug Exp $
29   *   *
30   *  Generic console support functions.   *  Generic console support functions.
31   *   *
32   *  This is used by individual device drivers, for example serial controllers,   *  This module is used by individual device drivers, for example serial
33   *  to attach stdin/stdout of the host system to a specific device.   *  controllers, keyboards, or other devices which need to attach to the
34     *  emulator's real stdin/stdout.
35   *   *
36   *  NOTE: This stuff is non-reentrant.   *  The idea is that several input and output streams (console handles) are
37     *  allowed. As long as the number of input streams is <= 1, then everything
38     *  can be done in the emulator's default terminal window.
39     *
40     *  If the number of inputs is more than 1, it is necessary to open up slave
41     *  xterm windows for each input. (Otherwise the behaviour is undefined; i.e.
42     *  which of two emulated serial controllers would get keyboard input?)
43     *
44     *  (If the -x command line option is NOT used, then slaves are not opened up.
45     *  Instead, a warning message is printed, and input is not allowed.)
46     *
47     *  Note that console handles that _allow_ input but are not yet used for
48     *  output are not counted. This allows a machine to have, say, 2 serial ports
49     *  which can be used for both input and output, and it will still be possible
50     *  to run in the default terminal window as long as only one of those serial
51     *  ports is actually used.
52     *
53     *  xterms are opened up "on demand", when output is sent to them.
54     *
55     *  The MAIN console handle (fixed as handle nr 0) is the one used by the
56     *  default terminal window. A machine which registers a serial controller,
57     *  which should be used as the main way of communicating with guest operating
58     *  systems running on that machine, should set machine->main_console_handle
59     *  to the handle of the correct port on that controller.
60     *
61     *
62     *  NOTE: The code in this module is mostly non-reentrant.
63   */   */
64    
65  #include <errno.h>  #include <errno.h>
# Line 49  Line 76 
76  #include "machine.h"  #include "machine.h"
77  #include "memory.h"  #include "memory.h"
78  #include "misc.h"  #include "misc.h"
79    #include "settings.h"
80    
81    
82  extern char *progname;  extern char *progname;
83    extern int verbose;
84    extern struct settings *global_settings;
85    
86    
87  static struct termios console_oldtermios;  static struct termios console_oldtermios;
# Line 62  static struct termios console_slave_tios Line 92  static struct termios console_slave_tios
92  static int console_slave_outputd;  static int console_slave_outputd;
93    
94  static int console_initialized = 0;  static int console_initialized = 0;
95    static struct settings *console_settings = NULL;
96  static int console_stdout_pending;  static int console_stdout_pending;
97    
98  #define CONSOLE_FIFO_LEN        4096  #define CONSOLE_FIFO_LEN        4096
99    
 /*  Mouse coordinates:  */  
 static int console_framebuffer_mouse_x;         /*  absolute x, 0-based  */  
 static int console_framebuffer_mouse_y;         /*  absolute y, 0-based  */  
 static int console_framebuffer_mouse_fb_nr;     /*  fb_number of last  
                                                     framebuffer cursor update */  
   
100  static int console_mouse_x;             /*  absolute x, 0-based  */  static int console_mouse_x;             /*  absolute x, 0-based  */
101  static int console_mouse_y;             /*  absolute y, 0-based  */  static int console_mouse_y;             /*  absolute y, 0-based  */
102  static int console_mouse_fb_nr;         /*  framebuffer number of  static int console_mouse_fb_nr;         /*  framebuffer number of
# Line 82  static int allow_slaves = 0; Line 107  static int allow_slaves = 0;
107    
108  struct console_handle {  struct console_handle {
109          int             in_use;          int             in_use;
110            int             in_use_for_input;
111          int             using_xterm;          int             using_xterm;
112          int             inputonly;          int             inputonly;
113            int             outputonly;
114            int             warning_printed;
115    
116            char            *machine_name;
117          char            *name;          char            *name;
118    
119          int             w_descriptor;          int             w_descriptor;
# Line 105  static int n_console_handles = 0; Line 134  static int n_console_handles = 0;
134    
135    
136  /*  /*
137   *  console_deinit():   *  console_deinit_main():
138   *   *
139   *  Restore host's console settings.   *  Restore host's console settings.
140   */   */
141  void console_deinit(void)  void console_deinit_main(void)
142  {  {
143          if (!console_initialized)          if (!console_initialized)
144                  return;                  return;
# Line 124  void console_deinit(void) Line 153  void console_deinit(void)
153   *  console_sigcont():   *  console_sigcont():
154   *   *
155   *  If the user presses CTRL-Z (to stop the emulator process) and then   *  If the user presses CTRL-Z (to stop the emulator process) and then
156   *  continues, we have to make sure that the right termios settings are   *  continues, the termios settings might have been invalidated. This
157   *  active.  (This should be set as the SIGCONT signal handler in src/emul.c.)   *  function restores them.
158     *
159     *  (This function should be set as the SIGCONT signal handler in src/emul.c.)
160   */   */
161  void console_sigcont(int x)  void console_sigcont(int x)
162  {  {
163          if (!console_initialized)          if (!console_initialized)
164                  return;                  return;
165    
166          /*  Make sure our 'current' termios setting is active:  */          /*  Make sure that the correct (current) termios setting is active:  */
167          tcsetattr(STDIN_FILENO, TCSANOW, &console_curtermios);          tcsetattr(STDIN_FILENO, TCSANOW, &console_curtermios);
168    
169          /*  Reset the signal handler:  */          /*  Reset the signal handler:  */
# Line 143  void console_sigcont(int x) Line 174  void console_sigcont(int x)
174  /*  /*
175   *  start_xterm():   *  start_xterm():
176   *   *
177   *  When using X11, this routine tries to start up an xterm, with another   *  When using X11 (well, when allow_slaves is set), this routine tries to
178   *  copy of gxemul inside. The other gxemul copy is given arguments   *  start up an xterm, with another copy of gxemul inside. The other gxemul
179   *  that will cause it to run console_slave().   *  copy is given arguments that will cause it to run console_slave().
180     *
181     *  TODO: This is ugly and hardcoded. Clean it up.
182   */   */
183  static void start_xterm(int handle)  static void start_xterm(int handle)
184  {  {
185          int filedes[2];          int filedes[2];
186          int filedesB[2];          int filedesB[2];
187          int res;          int res;
188            size_t mlen;
189          char **a;          char **a;
190          pid_t p;          pid_t p;
191    
# Line 173  static void start_xterm(int handle) Line 207  static void start_xterm(int handle)
207          /*  NOTE/warning: Hardcoded max nr of args!  */          /*  NOTE/warning: Hardcoded max nr of args!  */
208          a = malloc(sizeof(char *) * 20);          a = malloc(sizeof(char *) * 20);
209          if (a == NULL) {          if (a == NULL) {
210                  fprintf(stderr, "console_start_slave(): out of memory\n");                  fprintf(stderr, "start_xterm(): out of memory\n");
211                  exit(1);                  exit(1);
212          }          }
213    
# Line 183  static void start_xterm(int handle) Line 217  static void start_xterm(int handle)
217          a[1] = "-geometry";          a[1] = "-geometry";
218          a[2] = "80x25";          a[2] = "80x25";
219          a[3] = "-title";          a[3] = "-title";
220          a[4] = console_handles[handle].name;          mlen = strlen(console_handles[handle].name) +
221                strlen(console_handles[handle].machine_name) + 30;
222            a[4] = malloc(mlen);
223            snprintf(a[4], mlen, "GXemul: %s %s",
224                console_handles[handle].machine_name,
225                console_handles[handle].name);
226          a[5] = "-e";          a[5] = "-e";
227          a[6] = progname;          a[6] = progname;
228          a[7] = malloc(80);          a[7] = malloc(80);
# Line 192  static void start_xterm(int handle) Line 231  static void start_xterm(int handle)
231    
232          p = fork();          p = fork();
233          if (p == -1) {          if (p == -1) {
234                  printf("[ console_start_slave(): ERROR while trying to "                  printf("[ start_xterm(): ERROR while trying to "
235                      "fork(): %i ]\n", errno);                      "fork(): %i ]\n", errno);
236                  exit(1);                  exit(1);
237          } else if (p == 0) {          } else if (p == 0) {
# Line 201  static void start_xterm(int handle) Line 240  static void start_xterm(int handle)
240    
241                  p = setsid();                  p = setsid();
242                  if (p < 0)                  if (p < 0)
243                          printf("[ console_start_slave(): ERROR while trying "                          printf("[ start_xterm(): ERROR while trying "
244                              "to do a setsid(): %i ]\n", errno);                              "to do a setsid(): %i ]\n", errno);
245    
246                  res = execvp(a[0], a);                  res = execvp(a[0], a);
247                  printf("[ console_start_slave(): ERROR while trying to "                  printf("[ start_xterm(): ERROR while trying to "
248                      "execvp(\"");                      "execvp(\"");
249                  while (a[0] != NULL) {                  while (a[0] != NULL) {
250                          printf("%s", a[0]);                          printf("%s", a[0]);
# Line 214  static void start_xterm(int handle) Line 253  static void start_xterm(int handle)
253                          a++;                          a++;
254                  }                  }
255                  printf("\"): %i ]\n", errno);                  printf("\"): %i ]\n", errno);
256                    if (errno == ENOENT)
257                            printf("[ Most probably you don't have xterm"
258                                " in your PATH. Try again. ]\n");
259                  exit(1);                  exit(1);
260          }          }
261    
# Line 278  void console_makeavail(int handle, char Line 320  void console_makeavail(int handle, char
320   */   */
321  static int console_stdin_avail(int handle)  static int console_stdin_avail(int handle)
322  {  {
323            if (!console_handles[handle].in_use_for_input)
324                    return 0;
325    
326          if (!allow_slaves)          if (!allow_slaves)
327                  return d_avail(STDIN_FILENO);                  return d_avail(STDIN_FILENO);
328    
# Line 359  void console_putchar(int handle, int ch) Line 404  void console_putchar(int handle, int ch)
404  {  {
405          char buf[1];          char buf[1];
406    
407            if (!console_handles[handle].in_use_for_input &&
408                !console_handles[handle].outputonly)
409                    console_change_inputability(handle, 1);
410    
411          if (!allow_slaves) {          if (!allow_slaves) {
412                  /*  stdout:  */                  /*  stdout:  */
413                  putchar(ch);                  putchar(ch);
# Line 437  void console_mouse_button(int button, in Line 486  void console_mouse_button(int button, in
486    
487    
488  /*  /*
  *  console_get_framebuffer_mouse():  
  *  
  *  TODO: Comment  
  */  
 void console_get_framebuffer_mouse(int *x, int *y, int *fb_nr)  
 {  
         *x = console_framebuffer_mouse_x;  
         *y = console_framebuffer_mouse_y;  
         *fb_nr = console_framebuffer_mouse_fb_nr;  
 }  
   
   
 /*  
  *  console_set_framebuffer_mouse():  
  *  
  *  A framebuffer device calls this function when it sets the  
  *  position of a cursor (ie a mouse cursor).  
  */  
 void console_set_framebuffer_mouse(int x, int y, int fb_nr)  
 {  
         console_framebuffer_mouse_x = x;  
         console_framebuffer_mouse_y = y;  
         console_framebuffer_mouse_fb_nr = fb_nr;  
 }  
   
   
 /*  
489   *  console_getmouse():   *  console_getmouse():
490   *   *
491   *  Puts current mouse data into the variables pointed to by   *  Puts current mouse data into the variables pointed to by
# Line 520  void console_slave(char *arg) Line 542  void console_slave(char *arg)
542          int inputd;          int inputd;
543          int len;          int len;
544          char *p;          char *p;
545          char buf[400];          char buf[16384];
546    
547          /*  arg = '3,6' or similar, input and output descriptors  */          /*  arg = '3,6' or similar, input and output descriptors  */
548          /*  printf("console_slave(): arg = '%s'\n", arg);  */          /*  printf("console_slave(): arg = '%s'\n", arg);  */
# Line 566  void console_slave(char *arg) Line 588  void console_slave(char *arg)
588                          write(console_slave_outputd, buf, len);                          write(console_slave_outputd, buf, len);
589                  }                  }
590    
591                  usleep(100);                  usleep(10000);
592          }          }
593  }  }
594    
# Line 608  static struct console_handle *console_ne Line 630  static struct console_handle *console_ne
630          memset(chp, 0, sizeof(struct console_handle));          memset(chp, 0, sizeof(struct console_handle));
631    
632          chp->in_use = 1;          chp->in_use = 1;
633            chp->machine_name = "";
634          chp->name = strdup(name);          chp->name = strdup(name);
635          if (chp->name == NULL) {          if (chp->name == NULL) {
636                  printf("console_new_handle(): out of memory\n");                  printf("console_new_handle(): out of memory\n");
# Line 633  static struct console_handle *console_ne Line 656  static struct console_handle *console_ne
656   *   *
657   *  consolename should be something like "serial 0".   *  consolename should be something like "serial 0".
658   *   *
659     *  If use_for_input is 1, input is allowed right from the start. (This
660     *  can be upgraded later from 0 to 1 using the console_change_inputability()
661     *  function.)
662     *
663     *  If use_for_input is CONSOLE_OUTPUT_ONLY, then this is an output-only stream.
664     *
665   *  On success, an integer >= 0 is returned. This can then be used as a   *  On success, an integer >= 0 is returned. This can then be used as a
666   *  'handle' when writing to or reading from an emulated console.   *  'handle' when writing to or reading from an emulated console.
667   *   *
668   *  On failure, -1 is returned.   *  On failure, -1 is returned.
669   */   */
670  int console_start_slave(struct machine *machine, char *consolename)  int console_start_slave(struct machine *machine, char *consolename,
671            int use_for_input)
672  {  {
         int handle;  
         size_t mlen;  
673          struct console_handle *chp;          struct console_handle *chp;
674            int handle;
675    
676          if (machine == NULL || consolename == NULL) {          if (machine == NULL || consolename == NULL) {
677                  printf("console_start_slave(): NULL ptr\n");                  printf("console_start_slave(): NULL ptr\n");
# Line 650  int console_start_slave(struct machine * Line 679  int console_start_slave(struct machine *
679          }          }
680    
681          chp = console_new_handle(consolename, &handle);          chp = console_new_handle(consolename, &handle);
682            chp->in_use_for_input = use_for_input;
683          mlen = strlen(machine->name) + strlen(consolename) + 40;          if (use_for_input == CONSOLE_OUTPUT_ONLY) {
684          chp->name = malloc(mlen);                  chp->outputonly = 1;
685          if (chp->name == NULL) {                  chp->in_use_for_input = 0;
                 printf("out of memory\n");  
                 exit(1);  
686          }          }
         snprintf(chp->name, mlen, "GXemul: '%s' %s",  
             machine->name, consolename);  
687    
688  #if 0          if (machine->machine_name != NULL)
689          if (!machine->use_x11) {                  chp->machine_name = strdup(machine->machine_name);
690                  return handle;          else
691          }                  chp->machine_name = strdup("");
692  #endif  
693          chp->using_xterm = USING_XTERM_BUT_NOT_YET_OPEN;          chp->name = strdup(consolename);
694    
695            if (allow_slaves)
696                    chp->using_xterm = USING_XTERM_BUT_NOT_YET_OPEN;
697    
698          return handle;          return handle;
699  }  }
# Line 683  int console_start_slave(struct machine * Line 711  int console_start_slave(struct machine *
711   *   *
712   *  On failure, -1 is returned.   *  On failure, -1 is returned.
713   */   */
714  int console_start_slave_inputonly(struct machine *machine, char *consolename)  int console_start_slave_inputonly(struct machine *machine, char *consolename,
715            int use_for_input)
716  {  {
717          struct console_handle *chp;          struct console_handle *chp;
718          int handle;          int handle;
         size_t mlen;  
719    
720          if (machine == NULL || consolename == NULL) {          if (machine == NULL || consolename == NULL) {
721                  printf("console_start_slave(): NULL ptr\n");                  printf("console_start_slave(): NULL ptr\n");
# Line 696  int console_start_slave_inputonly(struct Line 724  int console_start_slave_inputonly(struct
724    
725          chp = console_new_handle(consolename, &handle);          chp = console_new_handle(consolename, &handle);
726          chp->inputonly = 1;          chp->inputonly = 1;
727            chp->in_use_for_input = use_for_input;
728            chp->machine_name = strdup(machine->name);
729            chp->name = strdup(consolename);
730    
731          mlen = strlen(machine->name) + strlen(consolename) + 40;          return handle;
732          chp->name = malloc(mlen);  }
733          if (chp->name == NULL) {  
734                  printf("out of memory\n");  
735    /*
736     *  console_change_inputability():
737     *
738     *  Sets whether or not a console handle can be used for input. Return value
739     *  is 1 if the change took place, 0 otherwise.
740     */
741    int console_change_inputability(int handle, int inputability)
742    {
743            int old;
744    
745            if (handle < 0 || handle >= n_console_handles) {
746                    fatal("console_change_inputability(): bad handle %i\n",
747                        handle);
748                  exit(1);                  exit(1);
749          }          }
         snprintf(chp->name, mlen, "GXemul: '%s' %s",  
             machine->name, consolename);  
750    
751          return handle;          old = console_handles[handle].in_use_for_input;
752            console_handles[handle].in_use_for_input = inputability;
753    
754            if (inputability != 0) {
755                    if (console_warn_if_slaves_are_needed(0)) {
756                            console_handles[handle].in_use_for_input = old;
757                            if (!console_handles[handle].warning_printed) {
758                                    fatal("%%\n%%  WARNING! Input to console ha"
759                                        "ndle \"%s\" wasn't enabled,\n%%  because "
760                                        "it", console_handles[handle].name);
761                                    fatal(" would interfere with other inputs,\n"
762                                        "%%  and you did not use the -x command "
763                                        "line option!\n%%\n");
764                            }
765                            console_handles[handle].warning_printed = 1;
766                            return 0;
767                    }
768            }
769    
770            return 1;
771  }  }
772    
773    
774  /*  /*
775   *  console_init_main():   *  console_init_main():
776   *   *
777   *  Put host's console into single-character (non-canonical) mode.   *  Puts the host's console into single-character (non-canonical) mode.
778   */   */
779  void console_init_main(struct emul *emul)  void console_init_main(struct emul *emul)
780  {  {
# Line 763  void console_init_main(struct emul *emul Line 824  void console_init_main(struct emul *emul
824    
825    
826  /*  /*
827     *  console_debug_dump():
828     *
829     *  Dump debug info, if verbose >= 2.
830     */
831    void console_debug_dump(struct machine *machine)
832    {
833            int i, iadd = DEBUG_INDENTATION, listed_main = 0;
834    
835            if (verbose < 2)
836                    return;
837    
838            debug("console slaves (xterms): %s\n", allow_slaves?
839                "yes" : "no");
840    
841            debug("console handles:\n");
842            debug_indentation(iadd);
843    
844            for (i=0; i<n_console_handles; i++) {
845                    if (!console_handles[i].in_use)
846                            continue;
847                    debug("%i: \"%s\"", i, console_handles[i].name);
848                    if (console_handles[i].using_xterm)
849                            debug(" [xterm]");
850                    if (console_handles[i].inputonly)
851                            debug(" [inputonly]");
852                    if (console_handles[i].outputonly)
853                            debug(" [outputonly]");
854                    if (i == machine->main_console_handle) {
855                            debug(" [MAIN CONSOLE]");
856                            listed_main = 1;
857                    }
858                    debug("\n");
859            }
860    
861            debug_indentation(-iadd);
862    
863            if (!listed_main)
864                    fatal("WARNING! no main console handle?\n");
865    }
866    
867    
868    /*
869   *  console_allow_slaves():   *  console_allow_slaves():
870   *   *
871   *  This function tells the console subsystem whether or not to open up   *  This function tells the console subsystem whether or not to open up
# Line 775  void console_allow_slaves(int allow) Line 878  void console_allow_slaves(int allow)
878    
879    
880  /*  /*
881     *  console_are_slaves_allowed():
882     *
883     *  Returns the value of allow_slaves.
884     */
885    int console_are_slaves_allowed(void)
886    {
887            return allow_slaves;
888    }
889    
890    
891    /*
892     *  console_warn_if_slaves_are_needed():
893     *
894     *  Prints an error (during startup of the emulator) if slave xterms are needed
895     *  (i.e. there is more than one console handle in use which is used for
896     *  INPUT), but they are not currently allowed.
897     *
898     *  This function should be called during startup (with init = 1), and every
899     *  time a console handle changes/upgrades its in_use_for_input from 0 to 1.
900     *
901     *  If init is non-zero, this function doesn't return if there was a warning.
902     *
903     *  If init is zero, no warning is printed. 1 is returned if there were more
904     *  than one input, 0 otherwise.
905     */
906    int console_warn_if_slaves_are_needed(int init)
907    {
908            int i, n = 0;
909    
910            if (allow_slaves)
911                    return 0;
912    
913            for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
914                    if (console_handles[i].in_use &&
915                        console_handles[i].in_use_for_input &&
916                        !console_handles[i].using_xterm)
917                            n ++;
918    
919            if (n > 1) {
920                    if (init) {
921                            fatal("#\n#  ERROR! More than one console input is "
922                                "in use,\n#  but xterm slaves are not enabled.\n"
923                                "#\n");
924                            fatal("#  Use -x to enable slave xterms.)\n#\n");
925                            for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
926                                    if (console_handles[i].in_use &&
927                                        console_handles[i].in_use_for_input &&
928                                        !console_handles[i].using_xterm)
929                                            fatal("#  console handle %i: '%s'\n",
930                                                i, console_handles[i].name);
931                            fatal("#\n");
932                            exit(1);
933                    }
934                    return 1;
935            }
936    
937            return 0;
938    }
939    
940    
941    /*
942   *  console_init():   *  console_init():
943   *   *
944   *  This function should be called before any other console_*() function   *  This function should be called before any other console_*() function
# Line 785  void console_init(void) Line 949  void console_init(void)
949          int handle;          int handle;
950          struct console_handle *chp;          struct console_handle *chp;
951    
952            console_settings = settings_new();
953    
954            settings_add(global_settings, "console", 1,
955                SETTINGS_TYPE_SUBSETTINGS, 0, console_settings);
956    
957            settings_add(console_settings, "allow_slaves", 0,
958                SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *)&allow_slaves);
959    
960          chp = console_new_handle("MAIN", &handle);          chp = console_new_handle("MAIN", &handle);
961          if (handle != MAIN_CONSOLE) {          if (handle != MAIN_CONSOLE) {
962                  printf("console_init(): fatal error: could not create"                  printf("console_init(): fatal error: could not create"
963                      " console 0: handle = %i\n", handle);                      " console 0: handle = %i\n", handle);
964                  exit(1);                  exit(1);
965          }          }
966    
967            chp->in_use_for_input = 1;
968    }
969    
970    
971    /*
972     *  console_deinit():
973     *
974     *  Unregister settings registered by console_init().
975     */
976    void console_deinit(void)
977    {
978            settings_remove(console_settings, "allow_slaves");
979            settings_remove(global_settings, "console");
980  }  }
981    

Legend:
Removed from v.10  
changed lines
  Added in v.34

  ViewVC Help
Powered by ViewVC 1.1.26