Skip to content

Commit 62cf542

Browse files
authored
Merge pull request #89 from huaxinliao/fb_vt
Support VT switching for fbdev backend
2 parents 053a651 + 6625eea commit 62cf542

File tree

2 files changed

+129
-20
lines changed

2 files changed

+129
-20
lines changed

backend/fbdev.c

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ typedef struct {
3030

3131
/* Linux virtual terminal (VT) */
3232
int vt_fd;
33+
bool vt_active;
34+
struct vt_mode old_vtm;
3335

3436
/* Linux framebuffer */
3537
int fb_fd;
@@ -86,22 +88,6 @@ static void twin_fbdev_get_screen_size(twin_fbdev_t *tx,
8688
*height = info.yres;
8789
}
8890

89-
static void twin_fbdev_damage(twin_screen_t *screen, twin_fbdev_t *tx)
90-
{
91-
int width, height;
92-
twin_fbdev_get_screen_size(tx, &width, &height);
93-
twin_screen_damage(tx->screen, 0, 0, width, height);
94-
}
95-
96-
static bool twin_fbdev_work(void *closure)
97-
{
98-
twin_screen_t *screen = SCREEN(closure);
99-
100-
if (twin_screen_damaged(screen))
101-
twin_screen_update(screen);
102-
return true;
103-
}
104-
10591
static inline bool twin_fbdev_is_rgb565(twin_fbdev_t *tx)
10692
{
10793
return tx->fb_var.red.offset == 11 && tx->fb_var.red.length == 5 &&
@@ -192,6 +178,50 @@ static bool twin_fbdev_apply_config(twin_fbdev_t *tx)
192178
return true;
193179
}
194180

181+
static void twin_fbdev_damage(twin_fbdev_t *tx)
182+
{
183+
int width, height;
184+
twin_fbdev_get_screen_size(tx, &width, &height);
185+
twin_screen_damage(tx->screen, 0, 0, width, height);
186+
}
187+
188+
static bool twin_fbdev_update_damage(void *closure)
189+
{
190+
twin_fbdev_t *tx = PRIV(closure);
191+
twin_screen_t *screen = SCREEN(closure);
192+
193+
if (!tx->vt_active && twin_screen_damaged(screen))
194+
twin_screen_update(screen);
195+
196+
return true;
197+
}
198+
199+
static bool twin_fbdev_work(void *closure)
200+
{
201+
twin_fbdev_t *tx = PRIV(closure);
202+
twin_screen_t *screen = SCREEN(closure);
203+
204+
if (tx->vt_active && (tx->fb_base != MAP_FAILED)) {
205+
/* Unmap the fbdev */
206+
munmap(tx->fb_base, tx->fb_len);
207+
tx->fb_base = MAP_FAILED;
208+
}
209+
210+
if (!tx->vt_active && (tx->fb_base == MAP_FAILED)) {
211+
/* Restore the fbdev settings */
212+
if (!twin_fbdev_apply_config(tx))
213+
log_error("Failed to apply configurations to the fbdev");
214+
215+
/* Mark entire screen for refresh */
216+
twin_screen_damage(screen, 0, 0, screen->width, screen->height);
217+
}
218+
219+
if (!tx->vt_active && twin_screen_damaged(screen))
220+
twin_screen_update(screen);
221+
222+
return true;
223+
}
224+
195225
twin_context_t *twin_fbdev_init(int width, int height)
196226
{
197227
char *fbdev_path = getenv(FBDEV_NAME);
@@ -218,10 +248,13 @@ twin_context_t *twin_fbdev_init(int width, int height)
218248
}
219249

220250
/* Set up virtual terminal environment */
221-
if (!twin_vt_setup(&tx->vt_fd)) {
251+
if (!twin_vt_setup(&tx->vt_fd, &tx->old_vtm, &tx->vt_active)) {
222252
goto bail_fb_fd;
223253
}
224254

255+
/* Set up signal handlers for switching TTYs */
256+
twin_vt_setup_signal_handler();
257+
225258
/* Apply configurations to the framebuffer device */
226259
if (!twin_fbdev_apply_config(tx)) {
227260
log_error("Failed to apply configurations to the framebuffer device");
@@ -254,6 +287,9 @@ twin_context_t *twin_fbdev_init(int width, int height)
254287
/* Setup file handler and work functions */
255288
twin_set_work(twin_fbdev_work, TWIN_WORK_REDISPLAY, ctx);
256289

290+
/* Register a callback function to handle damaged rendering */
291+
twin_screen_register_damaged(ctx->screen, twin_fbdev_update_damage, ctx);
292+
257293
return ctx;
258294

259295
bail_screen:
@@ -292,7 +328,6 @@ static void twin_fbdev_exit(twin_context_t *ctx)
292328
}
293329

294330
/* Register the Linux framebuffer backend */
295-
296331
const twin_backend_t g_twin_backend = {
297332
.init = twin_fbdev_init,
298333
.configure = twin_fbdev_configure,

backend/linux_vt.h

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,19 @@
1010
#include <fcntl.h>
1111
#include <linux/kd.h>
1212
#include <linux/vt.h>
13+
#include <signal.h>
1314
#include <stdlib.h>
1415
#include <sys/ioctl.h>
1516
#include "twin_private.h"
1617

1718
#define VT_DEV_TTY_MAX 11
19+
#define SIG_SWITCH_FROM SIGUSR1
20+
#define SIG_SWITCH_TO SIGUSR2
21+
22+
static volatile sig_atomic_t *vt_fd;
23+
24+
static volatile sig_atomic_t *is_vt_actived;
25+
1826
static inline int twin_vt_open(int vt_num)
1927
{
2028
int fd;
@@ -35,7 +43,42 @@ static inline int twin_vt_mode(int fd, int mode)
3543
return ioctl(fd, KDSETMODE, mode);
3644
}
3745

38-
static inline bool twin_vt_setup(int *fd_ptr)
46+
static void twin_vt_process_switch_signal(int signum)
47+
{
48+
if (signum == SIG_SWITCH_FROM) {
49+
/* Notify kernel to release current virtual terminal */
50+
ioctl(*vt_fd, VT_RELDISP, 1);
51+
52+
/* Set the virtual terminal display in text mode */
53+
ioctl(*vt_fd, KDSETMODE, KD_TEXT);
54+
55+
*is_vt_actived = true;
56+
} else if (signum == SIG_SWITCH_TO) {
57+
/* Switch complete */
58+
ioctl(*vt_fd, VT_RELDISP, VT_ACKACQ);
59+
60+
/* Restore the virtual terminal display in graphics mode */
61+
ioctl(*vt_fd, KDSETMODE, KD_GRAPHICS);
62+
63+
*is_vt_actived = false;
64+
}
65+
}
66+
67+
static inline void twin_vt_setup_signal_handler()
68+
{
69+
struct sigaction tty_sig = {.sa_handler = twin_vt_process_switch_signal};
70+
sigfillset(&tty_sig.sa_mask);
71+
72+
/* Set the signal handler for leaving the current TTY */
73+
sigaction(SIG_SWITCH_FROM, &tty_sig, NULL);
74+
75+
/* Set the signal handler for returning to the previous TTY */
76+
sigaction(SIG_SWITCH_TO, &tty_sig, NULL);
77+
}
78+
79+
static inline bool twin_vt_setup(int *fd_ptr,
80+
struct vt_mode *old_vtm,
81+
bool *vt_active)
3982
{
4083
/* Open VT0 to inquire information */
4184
if ((*fd_ptr = twin_vt_open(0)) < -1) {
@@ -57,12 +100,43 @@ static inline bool twin_vt_setup(int *fd_ptr)
57100
return false;
58101
}
59102

60-
/* Set VT to graphics mode to inhibit command-line text */
103+
/* Attempt to activate the specified virtual terminal by its number */
104+
if (ioctl(*fd_ptr, VT_ACTIVATE, vt_num) < 0) {
105+
log_error("Failed to activate VT %d", vt_num);
106+
return false;
107+
}
108+
109+
/* Wait until the specified virtual terminal becomes the active VT */
110+
if (ioctl(*fd_ptr, VT_WAITACTIVE, vt_num) < 0) {
111+
log_error("Failed to activate VT %d", vt_num);
112+
return false;
113+
}
114+
115+
/* Save the virtual terminal mode */
116+
if (ioctl(*fd_ptr, VT_GETMODE, &old_vtm) < 0) {
117+
log_error("Failed to get VT mode");
118+
return false;
119+
}
120+
121+
/* Set the virtual terminal mode */
122+
struct vt_mode vtm = {
123+
.mode = VT_PROCESS, .relsig = SIGUSR1, .acqsig = SIGUSR2};
124+
125+
if (ioctl(*fd_ptr, VT_SETMODE, &vtm) < 0) {
126+
log_error("Failed to set VT mode");
127+
return false;
128+
}
129+
130+
/* Set the virtual terminal display mode to graphics mode */
61131
if (twin_vt_mode(*fd_ptr, KD_GRAPHICS) < 0) {
62132
log_error("Failed to set KD_GRAPHICS mode");
133+
twin_vt_mode(*fd_ptr, KD_TEXT);
63134
return false;
64135
}
65136

137+
vt_fd = fd_ptr;
138+
is_vt_actived = vt_active;
139+
66140
return true;
67141
}
68142
#endif

0 commit comments

Comments
 (0)