unify messages, small readme update
[sdl_omap.git] / src / video / omapdss / osdl_video.c
CommitLineData
f641fccb 1/*
2 * (C) GraÅžvydas "notaz" Ignotas, 2010
3 *
4 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
5 * See the COPYING file in the top-level directory.
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <strings.h>
12#include <ctype.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <fcntl.h>
16#include <sys/ioctl.h>
17#include <unistd.h>
18#include <linux/fb.h>
19
20#include "omapsdl.h"
21#include "omapfb.h"
22#include "linux/fbdev.h"
23#include "linux/oshide.h"
24
25struct omapfb_saved_layer {
26 struct omapfb_plane_info pi;
27 struct omapfb_mem_info mi;
28};
29
30static int osdl_setup_omapfb(int fd, int enabled, int x, int y, int w, int h, int mem)
31{
32 struct omapfb_plane_info pi;
33 struct omapfb_mem_info mi;
34 int ret;
35
36 ret = ioctl(fd, OMAPFB_QUERY_PLANE, &pi);
37 if (ret != 0) {
7b66578c 38 err_perror("QUERY_PLANE");
f641fccb 39 return -1;
40 }
41
42 ret = ioctl(fd, OMAPFB_QUERY_MEM, &mi);
43 if (ret != 0) {
7b66578c 44 err_perror("QUERY_MEM");
f641fccb 45 return -1;
46 }
47
48 /* must disable when changing stuff */
49 if (pi.enabled) {
50 pi.enabled = 0;
51 ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
52 if (ret != 0)
7b66578c 53 err_perror("SETUP_PLANE");
f641fccb 54 }
55
56 mi.size = mem;
57 ret = ioctl(fd, OMAPFB_SETUP_MEM, &mi);
58 if (ret != 0) {
7b66578c 59 err_perror("SETUP_MEM");
f641fccb 60 return -1;
61 }
62
63 pi.pos_x = x;
64 pi.pos_y = y;
65 pi.out_width = w;
66 pi.out_height = h;
67 pi.enabled = enabled;
68
69 ret = ioctl(fd, OMAPFB_SETUP_PLANE, &pi);
70 if (ret != 0) {
7b66578c 71 err_perror("SETUP_PLANE");
f641fccb 72 return -1;
73 }
74
75 return 0;
76}
77
78static int read_sysfs(const char *fname, char *buff, size_t size)
79{
80 FILE *f;
81 int ret;
82
83 f = fopen(fname, "r");
84 if (f == NULL) {
7b66578c 85 err_perror("open %s: ", fname);
f641fccb 86 return -1;
87 }
88
89 ret = fread(buff, 1, size - 1, f);
90 fclose(f);
91 if (ret <= 0) {
7b66578c 92 err_perror("read %s: ", fname);
f641fccb 93 return -1;
94 }
95
96 buff[ret] = 0;
97 for (ret--; ret >= 0 && isspace(buff[ret]); ret--)
98 buff[ret] = 0;
99
100 return 0;
101}
102
103static int osdl_setup_omap_layer(struct SDL_PrivateVideoData *pdata,
104 const char *fbname, int width, int height, int bpp)
105{
106 int x = 0, y = 0, w = width, h = height; /* layer size and pos */
107 int screen_w = w, screen_h = h;
108 int fb_id, overlay_id = -1, screen_id = -1;
109 char buff[64], screen_name[64];
110 struct stat status;
111 const char *tmp;
112 int i, ret, fd;
113 FILE *f;
114
115 fd = open(fbname, O_RDWR);
116 if (fd == -1) {
7b66578c 117 err_perror("open %s", fbname);
f641fccb 118 return -1;
119 }
120
121 /* FIXME: assuming layer doesn't change here */
122 if (pdata->saved_layer == NULL) {
123 struct omapfb_saved_layer *slayer;
124 slayer = calloc(1, sizeof(*slayer));
125 if (slayer == NULL)
126 return -1;
127
128 ret = ioctl(fd, OMAPFB_QUERY_PLANE, &slayer->pi);
129 if (ret != 0) {
7b66578c 130 err_perror("QUERY_PLANE");
f641fccb 131 return -1;
132 }
133
134 ret = ioctl(fd, OMAPFB_QUERY_MEM, &slayer->mi);
135 if (ret != 0) {
7b66578c 136 err_perror("QUERY_MEM");
f641fccb 137 return -1;
138 }
139
140 pdata->saved_layer = slayer;
141 }
142
143 /* Figure out screen resolution, we will want to center if scaling is not enabled.
144 * The only way to achieve this seems to be walking some sysfs files.. */
145 ret = stat(fbname, &status);
146 if (ret != 0) {
7b66578c 147 err_perror("can't stat %s", fbname);
f641fccb 148 return -1;
149 }
150 fb_id = minor(status.st_rdev);
151
152 snprintf(buff, sizeof(buff), "/sys/class/graphics/fb%d/overlays", fb_id);
153 f = fopen(buff, "r");
154 if (f == NULL) {
7b66578c 155 err("can't open %s, skip screen detection", buff);
f641fccb 156 goto skip_screen;
157 }
158
159 ret = fscanf(f, "%d", &overlay_id);
160 fclose(f);
161 if (ret != 1) {
7b66578c 162 err("can't parse %s, skip screen detection", buff);
f641fccb 163 goto skip_screen;
164 }
165
166 snprintf(buff, sizeof(buff), "/sys/devices/platform/omapdss/overlay%d/manager", overlay_id);
167 ret = read_sysfs(buff, screen_name, sizeof(screen_name));
168 if (ret < 0) {
7b66578c 169 err("skip screen detection");
f641fccb 170 goto skip_screen;
171 }
172
173 for (i = 0; ; i++) {
174 snprintf(buff, sizeof(buff), "/sys/devices/platform/omapdss/display%d/name", i);
175 ret = read_sysfs(buff, buff, sizeof(buff));
176 if (ret < 0)
177 break;
178
179 if (strcmp(screen_name, buff) == 0) {
180 screen_id = i;
181 break;
182 }
183 }
184
185 if (screen_id < 0) {
7b66578c 186 err("could not find screen");
f641fccb 187 goto skip_screen;
188 }
189
190 snprintf(buff, sizeof(buff), "/sys/devices/platform/omapdss/display%d/timings", screen_id);
191 f = fopen(buff, "r");
192 if (f == NULL) {
7b66578c 193 err("can't open %s, skip screen detection", buff);
f641fccb 194 goto skip_screen;
195 }
196
197 ret = fscanf(f, "%*d,%d/%*d/%*d/%*d,%d/%*d/%*d/%*d", &screen_w, &screen_h);
198 fclose(f);
199 if (ret != 2) {
7b66578c 200 err("can't parse %s (%d), skip screen detection", buff, ret);
f641fccb 201 goto skip_screen;
202 }
203
7b66578c 204 log("detected %dx%d '%s' (%d) screen attached to fb %d and overlay %d",
f641fccb 205 screen_w, screen_h, screen_name, screen_id, fb_id, overlay_id);
206
207skip_screen:
208 tmp = getenv("SDL_OMAP_LAYER_SIZE");
209 if (tmp != NULL) {
210 int w_, h_;
211 if (strcasecmp(tmp, "fullscreen") == 0)
212 w = screen_w, h = screen_h;
213 else if (sscanf(tmp, "%dx%d", &w_, &h_) == 2)
214 w = w_, h = h_;
215 else
7b66578c 216 err("layer size specified incorrectly, "
217 "should be like 800x480");
f641fccb 218 }
219
220 x = screen_w / 2 - w / 2;
221 y = screen_h / 2 - h / 2;
222 ret = osdl_setup_omapfb(fd, 1, x, y, w, h, width * height * ((bpp + 7) / 8) * 3);
223 close(fd);
224
225 return ret;
226}
227
228int osdl_video_set_mode(struct SDL_PrivateVideoData *pdata, int width, int height, int bpp)
229{
230 const char *fbname;
231 int ret;
232
233 bpp = 16; // FIXME
234
235 fbname = getenv("SDL_FBDEV");
236 if (fbname == NULL)
237 fbname = "/dev/fb1";
238
239 if (pdata->fbdev != NULL) {
240 vout_fbdev_finish(pdata->fbdev);
241 pdata->fbdev = NULL;
242 }
243
244 omapsdl_config_from_env();
245
246 ret = osdl_setup_omap_layer(pdata, fbname, width, height, bpp);
247 if (ret < 0)
248 return -1;
249
250 pdata->fbdev = vout_fbdev_init(fbname, &width, &height, 0);
251 if (pdata->fbdev == NULL)
252 return -1;
253
254 if (!pdata->oshide_done) {
255 oshide_init();
256 pdata->oshide_done = 1;
257 }
258
259 return 0;
260}
261
262void *osdl_video_flip(struct SDL_PrivateVideoData *pdata)
263{
264 if (pdata->fbdev == NULL)
265 return NULL;
266
267 if (gcfg_force_vsync)
268 vout_fbdev_wait_vsync(pdata->fbdev);
269
270 return vout_fbdev_flip(pdata->fbdev);
271}
272
273void osdl_video_finish(struct SDL_PrivateVideoData *pdata)
274{
275 static const char *fbname;
276
277 fbname = getenv("SDL_FBDEV");
278 if (fbname == NULL)
279 fbname = "/dev/fb1";
280
281 if (pdata->fbdev != NULL) {
282 vout_fbdev_finish(pdata->fbdev);
283 pdata->fbdev = NULL;
284 }
285
286 /* restore the OMAP layer */
287 if (pdata->saved_layer != NULL) {
288 struct omapfb_saved_layer *slayer = pdata->saved_layer;
289 int fd;
290
291 fd = open(fbname, O_RDWR);
292 if (fd != -1) {
293 int enabled = slayer->pi.enabled;
294
295 /* be sure to disable while setting up */
296 slayer->pi.enabled = 0;
297 ioctl(fd, OMAPFB_SETUP_PLANE, &slayer->pi);
298 ioctl(fd, OMAPFB_SETUP_MEM, &slayer->mi);
299 if (enabled) {
300 slayer->pi.enabled = enabled;
301 ioctl(fd, OMAPFB_SETUP_PLANE, &slayer->pi);
302 }
303 close(fd);
304 }
305 free(slayer);
306 pdata->saved_layer = NULL;
307 }
308
309 if (pdata->oshide_done) {
310 oshide_finish();
311 pdata->oshide_done = 0;
312 }
313}
314