-
Notifications
You must be signed in to change notification settings - Fork 7
/
backend-mxc.c
110 lines (96 loc) · 2.95 KB
/
backend-mxc.c
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <mxc_epdc_fb_damage.h>
#include "backend.h"
struct mxc_data {
int fbfd;
int notify_fd;
};
#define MXC_EPDC_FB_DAMAGE_KO_ENV "MXC_EPDC_FB_DAMAGE_KO"
char __attribute__((weak)) mxc_epdc_fb_damage_ko_begin = 0;
char __attribute__((weak)) mxc_epdc_fb_damage_ko_end = 0;
static void ensure_have_fbdamage() {
if (faccessat(AT_FDCWD, "/dev/fbdamage", F_OK, AT_EACCESS) == 0) { return; }
char *start = &mxc_epdc_fb_damage_ko_begin;
size_t size = &mxc_epdc_fb_damage_ko_end-&mxc_epdc_fb_damage_ko_begin;
char *external = getenv(MXC_EPDC_FB_DAMAGE_KO_ENV);
int fd;
if (external) {
fd = open(external, O_RDONLY);
if (fd < 0) { return; }
struct stat stat;
if (fstat(fd, &stat)) { return; }
start = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (start == MAP_FAILED) { return; }
size = stat.st_size;
}
syscall(__NR_init_module, start, size, "");
if (external) {
munmap(start, size);
close(fd);
}
}
static void *mxc_initialize(void) {
struct mxc_data *d = malloc(sizeof(struct mxc_data));
if (!d) { return NULL; }
d->fbfd = open("/dev/fb0", O_RDONLY);
if (d->fbfd < 0) { free(d); return NULL; }
ensure_have_fbdamage();
d->notify_fd = open("/dev/fbdamage", O_RDONLY);
return d;
}
static struct fb_info mxc_get_info(void *d_) {
struct mxc_data *d = (struct mxc_data *)d_;
struct fb_var_screeninfo info;
ioctl(d->fbfd, FBIOGET_VSCREENINFO, &info);
__u32 bytes_per_pixel = info.bits_per_pixel / 8;
struct fb_info ret = {
.fd = d->fbfd,
.offset = bytes_per_pixel * (info.xoffset + info.yoffset * info.xres_virtual),
.len = info.xres_virtual * info.yres_virtual * bytes_per_pixel,
.xres = info.xres,
.yres = info.yres,
.bits_per_pixel = info.bits_per_pixel,
.line_width = info.xres_virtual * bytes_per_pixel,
.red = info.red,
.green = info.green,
.blue = info.blue,
};
return ret;
}
static int mxc_notification_fd(void *d_) {
return ((struct mxc_data *)d_)->notify_fd;
}
static struct update mxc_read_update(void *fb_voidp, int fd) {
struct mxcfb_damage_update damage;
size_t to_read = sizeof(struct mxcfb_damage_update);
char *p = (char*)&damage;
while (to_read > 0) {
size_t len = read(fd, p, to_read);
if (len == -1 && errno == EINTR) { continue; }
if (len < 0) { struct update ret = {0}; return ret; }
p += len;
to_read -= len;
};
struct mxcfb_rect *r = &damage.data.update_region;
struct update ret = {
.x1 = r->left, .y1 = r->top,
.x2 = r->left+r->width, .y2 = r->top+r->height
};
return ret;
}
struct backend mxc_backend = {
.name = "epdc_mxc_fb_damage",
.initialize = mxc_initialize,
.get_info = mxc_get_info,
.notification_fd = mxc_notification_fd,
.read_update = mxc_read_update,
};
DECLARE_BACKEND(mxc_backend)