wiz port. Lots of refactoring, some bugfixes
[ginge.git] / common / fbdev.c
... / ...
CommitLineData
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include <sys/ioctl.h>
8#include <sys/mman.h>
9#include <unistd.h>
10#include <linux/fb.h>
11#include <linux/matroxfb.h>
12
13#include "fbdev.h"
14
15#define FBDEV_MAX_BUFFERS 3
16
17struct vout_fbdev {
18 int fd;
19 void *mem;
20 size_t mem_size;
21 struct fb_var_screeninfo fbvar_old;
22 struct fb_var_screeninfo fbvar_new;
23 int buffer_write;
24 void *buffers[FBDEV_MAX_BUFFERS];
25 int buffer_count;
26};
27
28void *vout_fbdev_flip(struct vout_fbdev *fbdev)
29{
30 int draw_buf;
31
32 if (fbdev->buffer_count < 2)
33 return fbdev->mem;
34
35 draw_buf = fbdev->buffer_write;
36 fbdev->buffer_write++;
37 if (fbdev->buffer_write >= fbdev->buffer_count)
38 fbdev->buffer_write = 0;
39
40 fbdev->fbvar_new.yoffset = fbdev->fbvar_old.yres * draw_buf;
41
42 ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new);
43
44 return fbdev->buffers[fbdev->buffer_write];
45}
46
47void vout_fbdev_wait_vsync(struct vout_fbdev *fbdev)
48{
49 int arg = 0;
50 ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &arg);
51}
52
53void vout_fbdev_clear(struct vout_fbdev *fbdev)
54{
55 memset(fbdev->mem, 0, fbdev->mem_size);
56}
57
58struct vout_fbdev *vout_fbdev_init(const char *fbdev_name, int *w, int *h, int no_dblbuf)
59{
60 struct vout_fbdev *fbdev;
61 int i, ret;
62
63 fbdev = calloc(1, sizeof(*fbdev));
64 if (fbdev == NULL)
65 return NULL;
66
67 fbdev->fd = open(fbdev_name, O_RDWR);
68 if (fbdev->fd == -1) {
69 fprintf(stderr, "%s: ", fbdev_name);
70 perror("open");
71 goto fail_open;
72 }
73
74 ret = ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->fbvar_old);
75 if (ret == -1) {
76 perror("FBIOGET_VSCREENINFO ioctl");
77 goto fail;
78 }
79
80 fbdev->fbvar_new = fbdev->fbvar_old;
81 printf("%s: %ix%i@%d\n", fbdev_name, fbdev->fbvar_old.xres, fbdev->fbvar_old.yres,
82 fbdev->fbvar_old.bits_per_pixel);
83 *w = fbdev->fbvar_old.xres;
84 *h = fbdev->fbvar_old.yres;
85 fbdev->buffer_count = FBDEV_MAX_BUFFERS; // be optimistic
86 if (no_dblbuf)
87 fbdev->buffer_count = 1;
88
89 if (fbdev->fbvar_new.bits_per_pixel != 16) {
90 printf(" switching to 16bpp\n");
91 fbdev->fbvar_new.bits_per_pixel = 16;
92 ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new);
93 if (ret == -1) {
94 perror("FBIOPUT_VSCREENINFO ioctl");
95 goto fail;
96 }
97 }
98
99 if (fbdev->fbvar_new.yres_virtual < fbdev->fbvar_old.yres * fbdev->buffer_count) {
100 fbdev->fbvar_new.yres_virtual = fbdev->fbvar_old.yres * fbdev->buffer_count;
101 ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new);
102 if (ret == -1) {
103 fbdev->buffer_count = 1;
104 fprintf(stderr, "Warning: failed to increase virtual resolution, "
105 "doublebuffering disabled\n");
106 }
107 }
108
109 fbdev->mem_size = *w * *h * 2 * fbdev->buffer_count;
110 fbdev->mem = mmap(0, fbdev->mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0);
111 if (fbdev->mem == MAP_FAILED && fbdev->buffer_count > 1) {
112 fprintf(stderr, "Warning: can't map %zd bytes, doublebuffering disabled\n", fbdev->mem_size);
113 fbdev->mem_size = *w * *h * 2;
114 fbdev->buffer_count = 1;
115 fbdev->mem = mmap(0, fbdev->mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0);
116 }
117 if (fbdev->mem == MAP_FAILED) {
118 perror("mmap framebuffer");
119 goto fail;
120 }
121 memset(fbdev->mem, 0, fbdev->mem_size);
122 for (i = 0; i < fbdev->buffer_count; i++)
123 fbdev->buffers[i] = (char *)fbdev->mem + i * *w * *h * 2;
124
125 // some checks
126 ret = 0;
127 ret = ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &ret);
128 if (ret != 0)
129 fprintf(stderr, "Warning: vsync doesn't seem to be supported\n");
130
131 if (fbdev->buffer_count > 1) {
132 fbdev->buffer_write = 0;
133 fbdev->fbvar_new.yoffset = fbdev->fbvar_old.yres * (fbdev->buffer_count - 1);
134 ret = ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new);
135 if (ret != 0) {
136 fbdev->buffer_count = 1;
137 fprintf(stderr, "Warning: can't pan display, doublebuffering disabled\n");
138 }
139 }
140
141 printf("fbdev initialized.\n");
142 return fbdev;
143
144fail:
145 close(fbdev->fd);
146fail_open:
147 free(fbdev);
148 return NULL;
149}
150
151void vout_fbdev_finish(struct vout_fbdev *fbdev)
152{
153 ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_old);
154 if (fbdev->mem != MAP_FAILED)
155 munmap(fbdev->mem, fbdev->mem_size);
156 if (fbdev->fd >= 0)
157 close(fbdev->fd);
158 fbdev->mem = NULL;
159 fbdev->fd = -1;
160 free(fbdev);
161}
162
163#if 0
164void *g_screen_ptr;
165int main()
166{
167 int w, h;
168 vout_fbdev_init(&w, &h);
169 //while (1)
170 {
171 memset(g_screen_ptr, 0xff, fbdev_mem_size / 2);
172 plat_video_wait_vsync();
173 plat_video_flip();
174 memset(g_screen_ptr, 0x00, fbdev_mem_size / 2);
175 usleep(8000);
176// plat_video_wait_vsync();
177 plat_video_flip();
178 }
179}
180#endif