sndout_oss: rm incorrect O_ASYNC
[picodrive.git] / platform / linux / fbdev.c
CommitLineData
d08e7326 1#include <stdio.h>
b9fe67c6 2#include <stdlib.h>
d08e7326 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
d08e7326 13#include "fbdev.h"
14
15#define FBDEV_MAX_BUFFERS 3
16
b9fe67c6 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)
d08e7326 29{
30 int draw_buf;
31
b9fe67c6 32 if (fbdev->buffer_count < 2)
33 return fbdev->mem;
d08e7326 34
b9fe67c6 35 draw_buf = fbdev->buffer_write;
36 fbdev->buffer_write++;
37 if (fbdev->buffer_write >= fbdev->buffer_count)
38 fbdev->buffer_write = 0;
d08e7326 39
b9fe67c6 40 fbdev->fbvar_new.yoffset = fbdev->fbvar_old.yres * draw_buf;
89e6909b 41
b9fe67c6 42 ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new);
43
44 return fbdev->buffers[fbdev->buffer_write];
d08e7326 45}
46
b9fe67c6 47void vout_fbdev_wait_vsync(struct vout_fbdev *fbdev)
d08e7326 48{
49 int arg = 0;
b9fe67c6 50 ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &arg);
d08e7326 51}
52
b9fe67c6 53void vout_fbdev_clear(struct vout_fbdev *fbdev)
d08e7326 54{
b9fe67c6 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;
d08e7326 61 int i, ret;
62
b9fe67c6 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) {
d08e7326 69 fprintf(stderr, "%s: ", fbdev_name);
70 perror("open");
b9fe67c6 71 goto fail_open;
d08e7326 72 }
73
b9fe67c6 74 ret = ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->fbvar_old);
d08e7326 75 if (ret == -1) {
76 perror("FBIOGET_VSCREENINFO ioctl");
77 goto fail;
78 }
79
b9fe67c6 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;
d08e7326 88
b9fe67c6 89 if (fbdev->fbvar_new.bits_per_pixel != 16) {
d08e7326 90 printf(" switching to 16bpp\n");
b9fe67c6 91 fbdev->fbvar_new.bits_per_pixel = 16;
92 ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new);
d08e7326 93 if (ret == -1) {
94 perror("FBIOPUT_VSCREENINFO ioctl");
95 goto fail;
96 }
97 }
98
b9fe67c6 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);
d08e7326 102 if (ret == -1) {
b9fe67c6 103 fbdev->buffer_count = 1;
d08e7326 104 fprintf(stderr, "Warning: failed to increase virtual resolution, "
105 "doublebuffering disabled\n");
106 }
107 }
108
b9fe67c6 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);
d08e7326 116 }
b9fe67c6 117 if (fbdev->mem == MAP_FAILED) {
d08e7326 118 perror("mmap framebuffer");
119 goto fail;
120 }
b9fe67c6 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;
d08e7326 124
125 // some checks
126 ret = 0;
b9fe67c6 127 ret = ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &ret);
d08e7326 128 if (ret != 0)
129 fprintf(stderr, "Warning: vsync doesn't seem to be supported\n");
130
b9fe67c6 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);
d08e7326 135 if (ret != 0) {
b9fe67c6 136 fbdev->buffer_count = 1;
d08e7326 137 fprintf(stderr, "Warning: can't pan display, doublebuffering disabled\n");
138 }
139 }
140
141 printf("fbdev initialized.\n");
b9fe67c6 142 return fbdev;
d08e7326 143
144fail:
b9fe67c6 145 close(fbdev->fd);
146fail_open:
147 free(fbdev);
148 return NULL;
d08e7326 149}
150
b9fe67c6 151void vout_fbdev_finish(struct vout_fbdev *fbdev)
d08e7326 152{
b9fe67c6 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);
d08e7326 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