comparison old/framebuffer/cp_vt.c @ 0:04e28d8d3c6f

first commit
author Daiki KINJYO <e085722@ie.u-ryukyu.ac.jp>
date Mon, 08 Nov 2010 01:23:25 +0900
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:04e28d8d3c6f
1 // cp_vt.c
2 //
3 // Copyright (c) 2006, Mike Acton <macton@cellperformance.com>
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6 // documentation files (the "Software"), to deal in the Software without restriction, including without
7 // limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 // the Software, and to permit persons to whom the Software is furnished to do so, subject to the following
9 // conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in all copies or substantial
12 // portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
16 // EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
17 // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
18 // OR OTHER DEALINGS IN THE SOFTWARE.
19
20 // NOTES:
21 // From http://www.linuxjournal.com/article/2597
22 //
23 // "Console ttys are used when the keyboard and monitor are directly connected to the system without running
24 // the X Window System. Since you can have several virtual consoles, the devices are tty0 through tty63. In
25 // theory you can have 64 virtual consoles, but most people use only a few. The device /dev/console is
26 // identical to tty0 and is needed for historical reasons. If your system lets you log in on consoles 1
27 // through 6, then when you run X Windows System, X uses console 7, so you'll need /dev/tty1 through /dev/
28 // tty7 on your system. I recommend having files up through /dev/tty12. For more information on using
29 // virtual consoles, see the article Keyboards, Consoles and VT Cruising by John Fisk in the November 1996
30 // issue of Linux Journal"
31
32 #include <stdio.h>
33 #include <stdint.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <sys/ioctl.h>
37 #include <linux/vt.h>
38 #include <linux/kd.h>
39 #include "cp_vt.h"
40
41
42 static inline const char*
43 select_error_str( int existing_error, const char* const existing_error_str, int new_error, const char* const new_error_str )
44 {
45 // Only report the first error found - any error that follows is probably just a cascading effect.
46 const char* error_str = (char*)( (~(intptr_t)existing_error & (intptr_t)new_error & (intptr_t)new_error_str)
47 | ((intptr_t)existing_error & (intptr_t)existing_error_str) );
48
49 return (error_str);
50 }
51
52
53 int
54 cp_vt_open_graphics(cp_vt* restrict vt)
55 {
56 const char* error_str = NULL;
57 int error = 0;
58
59 // Open the current tty
60
61 // From http://tldp.org/HOWTO/Text-Terminal-HOWTO-6.html#ss6.3
62 // (An excellent overview by David S. Lawyer)
63 //
64 // "In Linux the PC monitor is usually called the console and has several device special files associated
65 // with it: vc/0 (tty0), vc/1 (tty1), vc/2 (tty2), etc. When you log in you are on vc/1. To go to vc/2
66 // (on the same screen) press down the 2 keys Alt(left)-F3. For vc/3 use Left Alt-F3, etc. These (vc/1,
67 // vc/2, vc/3, etc.) are called "virtual terminals". vc/0 (tty0) is just an alias for the current virtual
68 // terminal and it's where messages from the system are sent. Thus messages from the system will be seen
69 // on the console (monitor) regardless of which virtual terminal it is displaying."
70
71 const int cur_tty = open( "/dev/tty0", O_RDWR );
72 const int open_cur_tty_error = (cur_tty >> ((sizeof(int)*8)-1));
73 const char* open_cur_tty_error_str = "Could not open /dev/tty0. Check permissions.";
74
75 error_str = select_error_str( error, error_str, open_cur_tty_error, open_cur_tty_error_str );
76 error = error | open_cur_tty_error;
77
78 // From: http://www.linuxjournal.com/article/2783
79 // (A little out of date, but a nice primer.)
80 //
81 // "VT_GETSTATE returns the state of all VT's in the kernel in the structure:
82 //
83 // struct vt_stat {
84 // ushort v_active;
85 // ushort v_signal;
86 // ushort v_state;
87 // };
88 //
89 // v_active the currently active VT
90 // v_state mask of all the opened VT's
91 //
92 // v_active holds the number of the active VT (starting from 1), while v_state
93 // holds a mask where there is a 1 for each VT that has been opened by some process.
94 // Note that VT 0 is always opened in this scenario, since it refers to the current VT.
95 //
96 // Bugs:
97 // The v_signal member is unsupported."
98
99 struct vt_stat vts;
100
101 const int get_state_error = ioctl( cur_tty, VT_GETSTATE, &vts );
102 const char* get_state_error_str = "VT_GETSTATE failed on /dev/tty0";
103
104 error_str = select_error_str( error, error_str, get_state_error, get_state_error_str );
105 error = error | get_state_error;
106
107 vt->prev_tty_ndx = vts.v_active;
108
109 // From: http://opensolaris.org/os/project/vconsole/vt.7i.txt
110 // (Close enough to Linux and a pretty good source of documentation.)
111 //
112 // "VT_OPENQRY
113 // This call is used to find an available VT. The argu-
114 // ment to the ioctl is a pointer to an integer. The integer
115 // will be filled in with the number of the first avail-
116 // able VT that no other process has open (and hence, is
117 // available to be opened). If there are no available
118 // VTs, then -1 will be filled in."
119
120 const int open_query_error = ioctl( cur_tty, VT_OPENQRY, &vt->tty_ndx);
121 const char* open_query_error_str = "No open ttys available";
122
123 error_str = select_error_str( error, error_str, open_query_error, open_query_error_str );
124 error = error | open_query_error;
125
126 const int close_cur_tty_error = close( cur_tty );
127 const char* close_cur_tty_error_str = "Could not close parent tty";
128
129 error_str = select_error_str( error, error_str, close_cur_tty_error, close_cur_tty_error_str );
130 error = error | close_cur_tty_error;
131
132 char tty_file_name[11];
133
134 (void)snprintf( tty_file_name, 11, "/dev/tty%d", vt->tty_ndx );
135
136 const int tty = open( tty_file_name, O_RDWR );
137 const int open_tty_error = (cur_tty >> ((sizeof(int)*8)-1));
138 const char* open_tty_error_str = "Could not open tty";
139
140 error_str = select_error_str( error, error_str, open_tty_error, open_tty_error_str );
141 error = error | open_tty_error;
142
143 vt->tty = tty;
144
145 // From: http://opensolaris.org/os/project/vconsole/vt.7i.txt
146 // (Close enough to Linux and a pretty good source of documentation.)
147 //
148 // "VT_ACTIVATE
149 // This call has the effect of making the VT specified in
150 // the argument the active VT. The VT manager will cause
151 // a switch to occur in the same manner as if a hotkey had
152 // initiated the switch. If the specified VT is not open
153 // or does not exist the call will fail and errno will be
154 // set to ENXIO."
155 //
156 // "VT_WAITACTIVE
157 // If the specified VT is already active, this call
158 // returns immediately. Otherwise, it will sleep until
159 // the specified VT becomes active, at which point it will
160 // return."
161
162
163 const int activate_tty_error = ioctl( vt->tty, VT_ACTIVATE, vt->tty_ndx );
164 const char* activate_tty_error_str = "Could not activate tty";
165
166 error_str = select_error_str( error, error_str, activate_tty_error, activate_tty_error_str );
167 error = error | activate_tty_error;
168 #if 0
169 const int waitactive_tty_error = ioctl( vt->tty, VT_WAITACTIVE, vt->tty_ndx );
170 const char* waitactive_tty_error_str = "Could not switch to tty";
171
172 error_str = select_error_str( error, error_str, waitactive_tty_error, waitactive_tty_error_str );
173 error = error | waitactive_tty_error;
174 #endif
175
176 // From: http://opensolaris.org/os/project/vconsole/vt.7i.txt
177 // (Close enough to Linux and a pretty good source of documentation.)
178 //
179 // "KDSETMODE
180 // This call is used to set the text/graphics mode to the VT.
181 //
182 // KD_TEXT indicates that console text will be displayed on the screen
183 // with this VT. Normally KD_TEXT is combined with VT_AUTO mode for
184 // text console terminals, so that the console text display will
185 // automatically be saved and restored on the hot key screen switches.
186 //
187 // KD_GRAPHICS indicates that the user/application, usually Xserver,
188 // will have direct control of the display for this VT in graphics
189 // mode. Normally KD_GRAPHICS is combined with VT_PROCESS mode for
190 // this VT indicating direct control of the display in graphics mode.
191 // In this mode, all writes to this VT using the write system call are
192 // ignored, and the user is responsible for saving and restoring the
193 // display on the hot key screen switches."
194
195 // Save the current VT mode. This is most likely KD_TEXT.
196
197 const int kdgetmode_error = ioctl( vt->tty, KDGETMODE, &vt->prev_kdmode );
198 const char* kdgetmode_error_str = "Could not get mode for tty";
199
200 error_str = select_error_str( error, error_str, kdgetmode_error, kdgetmode_error_str );
201 error = error | kdgetmode_error;
202
203 // Set VT to GRAPHICS (user draw) mode
204
205 const int kdsetmode_graphics_error = ioctl( vt->tty, KDSETMODE, KD_GRAPHICS );
206 const char* kdsetmode_graphics_error_str = "Could not set graphics mode for tty";
207
208 error_str = select_error_str( error, error_str, kdsetmode_graphics_error, kdsetmode_graphics_error_str );
209 error = error | kdsetmode_graphics_error;
210
211 //
212 // Not bothering with VT_PROCESS, VT_AUTO is fine for our purposes.
213 //
214
215 // If vt blanking is active, for example when running this program from a remote terminal,
216 // setting KD_GRAPHICS will not disable the blanking. Reset to KD_TEXT from KD_GRAPHICS will
217 // force disable blanking. Then return to KD_GRAPHICS for drawing.
218 //
219 // Note: KD_TEXT (default) to KD_TEXT will do nothing, so blanking will not be disable unless
220 // the mode is changing. i.e. the initial set to KD_GRAPHICS above is useful.
221
222 const int kdsetmode_text_error = ioctl( vt->tty, KDSETMODE, KD_TEXT );
223 const char* kdsetmode_text_error_str = "Could not set text mode for tty";
224
225 error_str = select_error_str( error, error_str, kdsetmode_text_error, kdsetmode_text_error_str );
226 error = error | kdsetmode_text_error;
227
228 const int kdsetmode_graphics_reset_error = ioctl( vt->tty, KDSETMODE, KD_GRAPHICS );
229 const char* kdsetmode_graphics_reset_error_str = "Could not reset graphics mode for tty";
230
231 error_str = select_error_str( error, error_str, kdsetmode_graphics_reset_error, kdsetmode_graphics_reset_error_str );
232 error = error | kdsetmode_graphics_reset_error;
233
234 if ( error == -1 )
235 {
236 printf("ERROR: vt_graphics_open: %s\n",error_str);
237 return (-1);
238 }
239
240 return (0);
241 }
242
243 int
244 cp_vt_close(cp_vt* restrict vt)
245 {
246 const char* error_str = NULL;
247 int error = 0;
248
249 // Reset previous mode on tty (likely KD_TEXT)
250
251 const int kdsetmode_error = ioctl( vt->tty, KDSETMODE, vt->prev_kdmode );
252 const char* kdsetmode_error_str = "Could not reset previous mode for tty";
253
254 error_str = select_error_str( error, error_str, kdsetmode_error, kdsetmode_error_str );
255 error = error | kdsetmode_error;
256
257 // Restore previous tty
258
259 const int activate_tty_error = ioctl( vt->tty, VT_ACTIVATE, vt->prev_tty_ndx );
260 const char* activate_tty_error_str = "Could not activate previous tty";
261
262 error_str = select_error_str( error, error_str, activate_tty_error, activate_tty_error_str );
263 error = error | activate_tty_error;
264
265 const int waitactive_tty_error = ioctl( vt->tty, VT_WAITACTIVE, vt->prev_tty_ndx );
266 const char* waitactive_tty_error_str = "Could not switch to previous tty";
267
268 error_str = select_error_str( error, error_str, waitactive_tty_error, waitactive_tty_error_str );
269 error = error | waitactive_tty_error;
270
271 // Close tty
272
273 const int close_tty_error = close( vt->tty );
274 const char* close_tty_error_str = "Could not close tty";
275
276 error_str = select_error_str( error, error_str, close_tty_error, close_tty_error_str );
277 error = error | close_tty_error;
278
279 if ( error == -1 )
280 {
281 printf("ERROR: vt_close: %s\n",error_str);
282 return (-1);
283 }
284
285 return (0);
286 }