summaryrefslogtreecommitdiff
path: root/fb.c
blob: af1a8160cb850e130d30ca86760e8958360f2479 (plain)
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
111
112
113
114
115
116
117
118
119
120
121
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

#include <linux/mxcfb.h>
#include <sys/ioctl.h>

#include "fb.h"
#include "gpio.h"

#define WAVEFORM_MODE_INIT      0x0     /* Screen goes to white (clears) */
#define WAVEFORM_MODE_DU        0x1     /* Grey->white/grey->black */
#define WAVEFORM_MODE_GC16      0x2     /* High fidelity (flashing) */
#define WAVEFORM_MODE_GC4       0x3     /* Lower fidelity */
#define WAVEFORM_MODE_A2        0x4     /* Fast black/white animation */

static struct {
	int fd;
	unsigned char *addr;
	struct fb_fix_screeninfo fsi;
	struct fb_var_screeninfo vsi;
	size_t size;
} fb;

static void fb_update(int x, int y, int w, int h)
{
	static int marker = 0;
	marker++;

	struct mxcfb_update_data data = {
		.update_mode = UPDATE_MODE_PARTIAL,
		.waveform_mode = WAVEFORM_MODE_AUTO,
		.update_region.left = x,
		.update_region.top = y,
		.update_region.width = w,
		.update_region.height = h,
		.update_marker = marker,
		.temp = TEMP_USE_AMBIENT,
		.flags = 0,
	};
	printf("SEND_UPDATE: "); fflush(NULL); sync();
	int r = ioctl(fb.fd, MXCFB_SEND_UPDATE, &data);
	printf("%d\n", r); fflush(NULL); sync();

	struct mxcfb_update_marker_data md = {
		.update_marker = marker,
	};
	printf("WAIT_FOR_UPDATE_COMPLETE: "); fflush(NULL); sync();
	r = ioctl(fb.fd, MXCFB_WAIT_FOR_UPDATE_COMPLETE, &md);
	printf("%d\n", r); fflush(NULL); sync();
}

void fb_blank(void)
{
	printf("blanking screen\n");
	fflush(NULL); sync();
	memset(fb.addr, 0xff, fb.size);
	fb_update(0, 0, fb.vsi.xres, fb.vsi.yres);
}

void fb_loadimage(const char *path)
{
	printf("loading image %s\n", path);
	fflush(NULL); sync();

	int fd = open(path, O_RDONLY);
	if (fd == -1) {
		printf("not found\n");
		fflush(NULL);
		sync();
		return;
	}

	struct stat st;
	fstat(fd, &st);

	char *img = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
	if (img == MAP_FAILED) {
		printf("map failed\n");
		fflush(NULL);
		sync();
		return;
	}

	printf("copying image"); fflush(NULL); sync();
	for (uint32_t i = 0; i < fb.vsi.yres_virtual; i++) {
		printf("."); fflush(NULL); sync();
		memcpy(fb.addr + (i * fb.vsi.xres_virtual),
			img + (i * 936), fb.vsi.xres_virtual);
	}
	printf("\ndone\n"); fflush(NULL); sync();

	printf("munmap()\n"); fflush(NULL); sync();
	munmap(img, st.st_size);
	close(fd);

	fb_update(0, 0, fb.vsi.xres, fb.vsi.yres);
}

void fb_init(void)
{
	fb.fd = open("/dev/fb0", O_RDWR);

	ioctl(fb.fd, FBIOGET_FSCREENINFO, &fb.fsi);

	ioctl(fb.fd, FBIOGET_VSCREENINFO, &fb.vsi);

	fb.vsi.bits_per_pixel = 8;
	fb.vsi.grayscale = GRAYSCALE_8BIT;
	fb.vsi.activate = FB_ACTIVATE_FORCE;

	ioctl(fb.fd, FBIOPUT_VSCREENINFO, &fb.vsi);

	fb.size = fb.vsi.xres_virtual * fb.vsi.yres_virtual;
	fb.addr = mmap(NULL, fb.size, PROT_READ | PROT_WRITE, MAP_SHARED, fb.fd, 0);
}