almost
[fbgfx] / src / fbgfx.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/ioctl.h>
8 #include <sys/mman.h>
9 #include <linux/fb.h>
10 #include "fbgfx.h"
11
12 static void cleanup(void);
13
14 static int fd = -1;
15 static void *vmem;
16 static int vmem_size;
17 static struct fb_fix_screeninfo finfo;
18 static struct fb_var_screeninfo vinfo;
19 static struct fb_var_screeninfo saved_vinfo;
20 static int saved_vinfo_valid;
21
22 static int init(void)
23 {
24         if(fd >= 0) return 0;
25
26         if((fd = open("/dev/fb0", O_RDWR)) == -1) {
27                 fprintf(stderr, "failed to open framebuffer device\n");
28                 return -1;
29         }
30
31         ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
32
33         atexit(cleanup);
34         return 0;
35 }
36
37 static void cleanup(void)
38 {
39         if(vmem) {
40                 munmap(vmem, vmem_size);
41         }
42         if(fd != -1) {
43                 close(fd);
44         }
45 }
46
47 void *fbgfx_set_video_mode(int x, int y, int depth)
48 {
49         struct fb_var_screeninfo new_vinfo;
50
51         if(init() == -1) {
52                 return 0;
53         }
54
55         ioctl(fd, FBIOGET_VSCREENINFO, &new_vinfo);
56         new_vinfo.xres = x;
57         new_vinfo.yres = y;
58         new_vinfo.bits_per_pixel = depth;
59
60         if(ioctl(fd, FBIOPUT_VSCREENINFO, &new_vinfo) == -1) {
61                 fprintf(stderr, "failed to set video mode %dx%d %dbpp: %s\n", x, y, depth, strerror(errno));
62                 return 0;
63         }
64
65         if(vmem) {
66                 munmap(vmem, vmem_size);
67                 vmem = 0;
68                 vmem_size = 0;
69         }
70
71         return fbgfx_get_video_mode(0, 0, 0);
72 }
73
74 void *fbgfx_get_video_mode(int *xptr, int *yptr, int *depthptr)
75 {
76         if(init() == -1) {
77                 return 0;
78         }
79
80         ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
81         vmem_size = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
82
83         if(!vmem) {
84                 if((vmem = mmap(0, vmem_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (void*)-1) {
85                         fprintf(stderr, "failed to map video memory\n");
86                         vmem = 0;
87                         return 0;
88                 }
89         }
90         if(xptr) *xptr = vinfo.xres;
91         if(yptr) *yptr = vinfo.yres;
92         if(depthptr) *depthptr = vinfo.bits_per_pixel;
93         return vmem;
94 }
95
96 void fbgfx_save_video_mode(void)
97 {
98         if(init() == -1) {
99                 return;
100         }
101
102         if(ioctl(fd, FBIOGET_VSCREENINFO, &saved_vinfo) == -1) {
103                 return;
104         }
105         saved_vinfo_valid = 1;
106 }
107
108 void fbgfx_restore_video_mode(void)
109 {
110         if(init() == -1 || !saved_vinfo_valid) {
111                 return;
112         }
113         ioctl(fd, FBIOPUT_VSCREENINFO, &saved_vinfo);
114 }