21
21
#define FBDEV_DEFAULT "/dev/fb0"
22
22
#define SCREEN (x ) ((twin_context_t *) x)->screen
23
23
#define PRIV (x ) ((twin_fbdev_t *) ((twin_context_t *) x)->priv)
24
+ #define SIG_SWITCH_FROM SIGUSR1
25
+ #define SIG_SWITCH_TO SIGUSR2
26
+
27
+ static twin_context_t * global_ctx ;
24
28
25
29
typedef struct {
26
30
twin_screen_t * screen ;
@@ -30,6 +34,8 @@ typedef struct {
30
34
31
35
/* Linux virtual terminal (VT) */
32
36
int vt_fd ;
37
+ bool vt_active ;
38
+ struct vt_mode old_vtm ;
33
39
34
40
/* Linux framebuffer */
35
41
int fb_fd ;
@@ -38,8 +44,8 @@ typedef struct {
38
44
uint16_t cmap [3 ][256 ];
39
45
uint8_t * fb_base ;
40
46
size_t fb_len ;
41
- } twin_fbdev_t ;
42
47
48
+ } twin_fbdev_t ;
43
49
/* color conversion */
44
50
#define ARGB32_TO_RGB565_PERLINE (dest , pixels , width ) \
45
51
do { \
@@ -93,12 +99,25 @@ static void twin_fbdev_damage(twin_screen_t *screen, twin_fbdev_t *tx)
93
99
twin_screen_damage (tx -> screen , 0 , 0 , width , height );
94
100
}
95
101
102
+ static bool twin_fbdev_damaged (void * closure )
103
+ {
104
+ twin_fbdev_t * tx = PRIV (closure );
105
+ twin_screen_t * screen = SCREEN (closure );
106
+
107
+ if (!tx -> vt_active && twin_screen_damaged (screen ))
108
+ twin_screen_update (screen );
109
+
110
+ return true;
111
+ }
112
+
96
113
static bool twin_fbdev_work (void * closure )
97
114
{
115
+ twin_fbdev_t * tx = PRIV (closure );
98
116
twin_screen_t * screen = SCREEN (closure );
99
117
100
- if (twin_screen_damaged (screen ))
118
+ if (! tx -> vt_active && twin_screen_damaged (screen ))
101
119
twin_screen_update (screen );
120
+
102
121
return true;
103
122
}
104
123
@@ -192,6 +211,53 @@ static bool twin_fbdev_apply_config(twin_fbdev_t *tx)
192
211
return true;
193
212
}
194
213
214
+ static void handle_tty_signal (int signum )
215
+ {
216
+ twin_fbdev_t * tx = PRIV (global_ctx );
217
+ twin_screen_t * screen = SCREEN (global_ctx );
218
+
219
+ if (signum == SIG_SWITCH_FROM ) {
220
+ /* Notify kernel to release current virtual terminal */
221
+ ioctl (tx -> vt_fd , VT_RELDISP , 1 );
222
+
223
+ /* Set the virtual terminal display in text mode */
224
+ ioctl (tx -> vt_fd , KDSETMODE , KD_TEXT );
225
+
226
+ tx -> vt_active = true;
227
+
228
+ if (tx -> fb_base != MAP_FAILED )
229
+ munmap (tx -> fb_base , tx -> fb_len );
230
+ tx -> fb_base = MAP_FAILED ;
231
+ } else if (signum == SIG_SWITCH_TO ) {
232
+ /* Switch complete */
233
+ ioctl (tx -> vt_fd , VT_RELDISP , VT_ACKACQ );
234
+
235
+ /* Restore the virtual terminal display in graphics mode */
236
+ ioctl (tx -> vt_fd , KDSETMODE , KD_GRAPHICS );
237
+
238
+ /* Restore fbdev settings */
239
+ if (twin_fbdev_apply_config (tx )) {
240
+ tx -> vt_active = 0 ;
241
+
242
+ /* Mark entire screen for refresh */
243
+ twin_screen_damage (screen , 0 , 0 , screen -> width , screen -> height );
244
+ }
245
+ }
246
+ }
247
+
248
+ static void twin_vt_setup_signal_handler (int * fd_ptr )
249
+ {
250
+ struct sigaction tty_sig ;
251
+ tty_sig .sa_handler = handle_tty_signal ;
252
+ sigfillset (& tty_sig .sa_mask );
253
+
254
+ /* Set the signal handler for leaving the current TTY */
255
+ sigaction (SIG_SWITCH_FROM , & tty_sig , NULL );
256
+
257
+ /* Set the signal handler for returning to the previous TTY */
258
+ sigaction (SIG_SWITCH_TO , & tty_sig , NULL );
259
+ }
260
+
195
261
twin_context_t * twin_fbdev_init (int width , int height )
196
262
{
197
263
char * fbdev_path = getenv (FBDEV_NAME );
@@ -204,6 +270,8 @@ twin_context_t *twin_fbdev_init(int width, int height)
204
270
twin_context_t * ctx = calloc (1 , sizeof (twin_context_t ));
205
271
if (!ctx )
206
272
return NULL ;
273
+
274
+ global_ctx = ctx ;
207
275
ctx -> priv = calloc (1 , sizeof (twin_fbdev_t ));
208
276
if (!ctx -> priv )
209
277
return NULL ;
@@ -218,10 +286,13 @@ twin_context_t *twin_fbdev_init(int width, int height)
218
286
}
219
287
220
288
/* Set up virtual terminal environment */
221
- if (!twin_vt_setup (& tx -> vt_fd )) {
289
+ if (!twin_vt_setup (& tx -> vt_fd , & tx -> old_vtm )) {
222
290
goto bail_fb_fd ;
223
291
}
224
292
293
+ /* Set up signal handlers for switching TTYs */
294
+ twin_vt_setup_signal_handler (& tx -> vt_fd );
295
+
225
296
/* Apply configurations to the framebuffer device */
226
297
if (!twin_fbdev_apply_config (tx )) {
227
298
log_error ("Failed to apply configurations to the framebuffer device" );
@@ -254,6 +325,9 @@ twin_context_t *twin_fbdev_init(int width, int height)
254
325
/* Setup file handler and work functions */
255
326
twin_set_work (twin_fbdev_work , TWIN_WORK_REDISPLAY , ctx );
256
327
328
+ /* Register a callback function to handle damaged rendering */
329
+ twin_screen_register_damaged (ctx -> screen , twin_fbdev_damaged , ctx );
330
+
257
331
return ctx ;
258
332
259
333
bail_screen :
@@ -282,7 +356,7 @@ static void twin_fbdev_exit(twin_context_t *ctx)
282
356
return ;
283
357
284
358
twin_fbdev_t * tx = PRIV (ctx );
285
- twin_vt_mode (tx -> vt_fd , KD_TEXT );
359
+ twin_vt_display_mode (tx -> vt_fd , KD_TEXT );
286
360
munmap (tx -> fb_base , tx -> fb_len );
287
361
twin_linux_input_destroy (tx -> input );
288
362
close (tx -> vt_fd );
@@ -292,7 +366,6 @@ static void twin_fbdev_exit(twin_context_t *ctx)
292
366
}
293
367
294
368
/* Register the Linux framebuffer backend */
295
-
296
369
const twin_backend_t g_twin_backend = {
297
370
.init = twin_fbdev_init ,
298
371
.configure = twin_fbdev_configure ,
0 commit comments