-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathfbdev.c
More file actions
88 lines (77 loc) · 2.43 KB
/
fbdev.c
File metadata and controls
88 lines (77 loc) · 2.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#define _GNU_SOURCE
#include "config.h"
#include "display.h"
#include <fcntl.h>
#include <linux/fb.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
/* Attempt to unblank fb via sysfs; non-fatal if unavailable. */
static void sysfs_unblank(const char *path) {
int fd = open(path, O_WRONLY | O_CLOEXEC);
if (fd < 0) return;
(void)write(fd, "0\n", 2);
close(fd);
}
bool fbdev_init(DisplayDev *d) {
d->fd = open(FB_DEVICE, O_RDWR | O_CLOEXEC);
if (d->fd < 0)
d->fd = open(FB_DEVICE_ALT, O_RDWR | O_CLOEXEC);
if (d->fd < 0)
return false;
/* Proactively unblank via sysfs – some Android kernels ignore FBIOBLANK. */
sysfs_unblank("/sys/class/graphics/fb0/blank");
sysfs_unblank("/sys/class/graphics/fb1/blank");
struct fb_var_screeninfo vi;
struct fb_fix_screeninfo fi;
if (ioctl(d->fd, FBIOGET_VSCREENINFO, &vi) < 0 ||
ioctl(d->fd, FBIOGET_FSCREENINFO, &fi) < 0) {
close(d->fd);
d->fd = -1;
return false;
}
/* Ensure screen is on before mapping. */
ioctl(d->fd, FBIOBLANK, FB_BLANK_UNBLANK);
d->width = (int)vi.xres;
d->height = (int)vi.yres;
d->buf.pitch = fi.line_length;
d->buf.size = fi.smem_len;
d->buf.conn_id = 0;
d->buf.crtc_id = 0;
/* Guard: zero-pitch or zero-length means driver is broken. */
if (d->buf.pitch == 0 || d->buf.size == 0) {
/* Compute a sane fallback. */
if (d->buf.pitch == 0)
d->buf.pitch = (uint32_t)(d->width * 4);
if (d->buf.size == 0)
d->buf.size = d->buf.pitch * (uint32_t)d->height;
}
d->buf.map = mmap(NULL, d->buf.size, PROT_READ | PROT_WRITE,
MAP_SHARED, d->fd, 0);
if (d->buf.map == MAP_FAILED) {
close(d->fd);
d->fd = -1;
return false;
}
d->is_drm = false;
memset(d->buf.map, 0, d->buf.size);
return true;
}
/* Hardware blank/unblank via FBIOBLANK ioctl (preferred over sysfs). */
void fbdev_blank(DisplayDev *d, bool blank) {
if (d->fd < 0) return;
ioctl(d->fd, FBIOBLANK,
blank ? (int)FB_BLANK_POWERDOWN : (int)FB_BLANK_UNBLANK);
}
/* Pan to offset 0 – flushes the rendered frame on double-buffered devices;
* a no-op on single-buffered hardware (writes are directly visible). */
void fbdev_kick(DisplayDev *d) {
if (d->fd < 0 || d->buf.pitch == 0) return;
struct fb_var_screeninfo vi;
if (ioctl(d->fd, FBIOGET_VSCREENINFO, &vi) == 0) {
vi.xoffset = 0;
vi.yoffset = 0;
ioctl(d->fd, FBIOPAN_DISPLAY, &vi);
}
}