1 /* Implementation of an abstract terminal controller. 2 Copyright 2002 Paul Twohey. 3 4 This file is part of VMIPS. 5 6 VMIPS is free software; you can redistribute it and/or modify it 7 under the terms of the GNU General Public License as published by the 8 Free Software Foundation; either version 2 of the License, or (at your 9 option) any later version. 10 11 VMIPS is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 for more details. 15 16 You should have received a copy of the GNU General Public License along 17 with VMIPS; if not, write to the Free Software Foundation, Inc., 18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 19 20 #ifndef _TERMINALCONTROLLER_H_ 21 #define _TERMINALCONTROLLER_H_ 22 23 #include "devreg.h" 24 #include "task.h" 25 #include <new> 26 #include <sys/types.h> 27 #include <termios.h> 28 class Clock; 29 30 // XXX Maximum number of terminals the controller supports. 31 #define MAX_TERMINALS 16 32 33 /* A keyboard can be in one of two states: READY or UNREADY. The state READY 34 corresponds to when the keyboard has new data the simulated program hasn't 35 yet read. In the READY state the keyboard will check for new data every 36 keyboard_repoll_ns nanoseconds and replace the old data with the new data. 37 The keyboard transitions to the UNREADY state when the simulated program 38 reads the keyboard data. In the UNREADY state the keyboard will poll for 39 new data every keyboard_poll_ns nanoseconds. When the keyboard detects 40 data it will transition to the READY state. The keyboard is initially in 41 the UNREADY state. 42 43 A display can be in one of two states: READY or UNREADY. The state READY 44 corresponds to when the display is able to accept a new character to 45 write out. The display transitions to the UNREADY state when a character 46 is written to the display data register. In the UNREADY state the display 47 ignores rights. The display transitions to the READY state after 48 display_ready_delay_ns nanoseconds. The display is initially in the READY 49 state. 50 */ 51 52 class TerminalController 53 { 54 public: 55 /* Create a new TerminalController which uses CLOCK as its time base. 56 KEYBOARD_POLL_NS is the positive time in nanoseconds that the 57 keyboards are polled for input. KEYBOARD_REPOLL_NS is the positive 58 time in nanoseconds that a READY keyboard will wait to repoll for 59 data. DISPLAY_READY_DELAY_NS is the positive time in nanoseconds 60 that a display will wait to transition from the UNREADY to the 61 READY state. */ 62 TerminalController( Clock *clock, long keyboard_poll_ns, 63 long keyboard_repoll_ns, 64 long display_ready_delay_ns ); 65 66 /* Reset and close all the terminal file descriptors. */ 67 virtual ~TerminalController(); 68 69 /* Connect the terminal with file descriptor TTY_FD to the simulated 70 terminal line LINE. Save the initial terminal state, then configure 71 the terminal for use as a simulated terminal. The controller now 72 owns the file descriptor and is responsible for restoring its 73 state and closing it. Returns true if the terminal was connected 74 sucessfully, otherwise closes FD and returns false. */ 75 virtual bool connect_terminal( int tty_fd, int line ); 76 77 /* Remove the terminal on line LINE. Has no effect if there is no 78 terminal on line LINE. Restore the original terminal settings 79 for the line and then close its associated file descriptor. */ 80 virtual void remove_terminal( int line ); 81 82 /* Reinitialize terminals to the state they were in when VMIPS started. 83 This is the opposite of reinitialize_terminals(). */ 84 virtual void suspend (); 85 86 /* Return true if line LINE is connected, false otherwise. */ line_connected(const int line)87 bool line_connected (const int line) const { 88 return line >= 0 && line < MAX_TERMINALS && lines[line].tty_fd != -1; 89 } 90 91 /* Reinitialize terminals to a state suitable for use as part of a 92 vmips simulation. Useful for restoring tty settings when vmips 93 is moved to the forground after being backgrounded. */ 94 virtual void reinitialize_terminals(); 95 96 /* Poll all the keyboards for new data to read. If data is available 97 read it in and adjust the keyboard state accordingly. For each 98 keyboard with data available, schedule a KeyboardWait object to 99 enforce the simulated delay between data checks. */ 100 virtual void poll_keyboards(); 101 102 /* Helper routine to repoll the keyboard. */ 103 virtual void repoll_keyboard( int line ); 104 105 /* Write characater DATA to the terminal on line LINE and transition 106 the display from the READY and UNREADY states to the UNREADY state. 107 This should only be called for connected lines. */ 108 virtual void unready_display( int line, char data ); 109 110 /* Transition the display on line LINE from the UNREADY state into 111 the READY state. Should only be called for connected lines in the 112 UNREADY state. */ 113 virtual void ready_display( int line ); 114 115 /* Transition the keyboard on line LINE from the READY state into 116 the UNREADY state. Should only be called for connected lines in 117 the the READY state. */ 118 virtual void unready_keyboard( int line ); 119 120 protected: 121 /* Transition the keyboard from the READY or UNREADY states to the 122 READY state. Read data from the keyboard on line LINE. Should only 123 be called on connected lines. */ 124 virtual void ready_keyboard( int line ); 125 126 /* Take connected (or partially connected) line LINE and prepare it 127 for use as part of a simulated console device. Returns true if the 128 preparation was sucessful, false otherwise. */ 129 virtual bool prepare_tty( int line ); 130 131 protected: 132 class DisplayDelay : public CancelableTask 133 { 134 public: 135 DisplayDelay(TerminalController *controller, int line); 136 ~DisplayDelay(); 137 138 protected: 139 /* Make READY display on line LINE on controller CONTROLLER. */ 140 virtual void real_task(); 141 142 protected: 143 TerminalController *controller; 144 int line; 145 }; 146 147 class KeyboardRepoll : public CancelableTask 148 { 149 public: 150 KeyboardRepoll(TerminalController *controller,int line); 151 virtual ~KeyboardRepoll(); 152 153 protected: 154 /* Repoll keyboard on line LINE of controller CONTROLLER. */ 155 virtual void real_task(); 156 157 protected: 158 TerminalController *controller; 159 int line; 160 }; 161 162 class KeyboardPoll : public CancelableTask 163 { 164 public: 165 KeyboardPoll(TerminalController *controller); 166 virtual ~KeyboardPoll(); 167 168 protected: 169 /* Poll all unready keyboards for new data. */ 170 virtual void real_task(); 171 172 protected: 173 TerminalController *controller; 174 }; 175 176 protected: 177 const long keyboard_poll_ns; // UNREADY->READY keyboard poll 178 const long keyboard_repoll_ns; // READY keyboard repoll 179 const long display_ready_delay_ns; // display READY->UNREADY delay 180 181 KeyboardPoll *keyboard_poll; // current keyboard poll 182 Clock *clock; 183 int max_fd; // cache of largest fd + 1 184 fd_set unready_keyboards; // unready keyboard descriptors 185 186 /* Make a copy of unready_keyboards in SET. */ copy_unready_keyboards(fd_set * set)187 void copy_unready_keyboards (fd_set *set) { 188 *set = unready_keyboards; 189 } 190 191 enum State { 192 UNREADY = 0, 193 READY = CTL_RDY, 194 }; 195 196 struct LineState { 197 termios tty_state; 198 int tty_fd; 199 KeyboardRepoll *keyboard_repoll; 200 DisplayDelay *display_delay; 201 char keyboard_char; 202 State keyboard_state; 203 State display_state; 204 }; 205 206 LineState lines[ MAX_TERMINALS ]; 207 }; 208 209 #endif /* _TERMINALCONTROLLER_H_ */ 210