305
|
1 /*
|
|
2 * Video driver for Framebuffer device
|
|
3 * by Szabolcs Berecz <szabi@inf.elte.hu>
|
359
|
4 * (C) 2001
|
305
|
5 *
|
|
6 * Some idea and code borrowed from Chris Lawrence's ppmtofb-0.27
|
|
7 */
|
|
8
|
393
|
9 #define FBDEV "fbdev: "
|
|
10
|
225
|
11 #include <stdio.h>
|
|
12 #include <stdlib.h>
|
|
13 #include <string.h>
|
|
14 #include <fcntl.h>
|
|
15 #include <unistd.h>
|
|
16 #include <errno.h>
|
359
|
17 #include <ctype.h>
|
|
18 #include <assert.h>
|
225
|
19
|
|
20 #include <sys/mman.h>
|
|
21 #include <sys/ioctl.h>
|
2354
|
22 #include <sys/kd.h>
|
225
|
23 #include <linux/fb.h>
|
|
24
|
|
25 #include "config.h"
|
|
26 #include "video_out.h"
|
|
27 #include "video_out_internal.h"
|
658
|
28 #include "fastmemcpy.h"
|
633
|
29 #include "sub.h"
|
2556
|
30 #include "../postproc/rgb2rgb.h"
|
4089
|
31 #ifdef CONFIG_VIDIX
|
4084
|
32 #include "vosub_vidix.h"
|
4089
|
33 #endif
|
4084
|
34 #include "aspect.h"
|
225
|
35
|
4756
|
36 #ifdef HAVE_PNG
|
|
37 extern vo_functions_t video_out_png;
|
|
38 #endif
|
|
39
|
225
|
40 LIBVO_EXTERN(fbdev)
|
|
41
|
|
42 static vo_info_t vo_info = {
|
|
43 "Framebuffer Device",
|
|
44 "fbdev",
|
|
45 "Szabolcs Berecz <szabi@inf.elte.hu>",
|
|
46 ""
|
|
47 };
|
|
48
|
379
|
49 extern int verbose;
|
|
50
|
4089
|
51 #ifdef CONFIG_VIDIX
|
4084
|
52 /* Name of VIDIX driver */
|
|
53 static const char *vidix_name = NULL;
|
4386
|
54 #endif
|
6164
|
55 static signed int pre_init_err = -2;
|
359
|
56 /******************************
|
393
|
57 * fb.modes support *
|
359
|
58 ******************************/
|
|
59
|
7069
|
60 extern char *monitor_hfreq_str;
|
|
61 extern char *monitor_vfreq_str;
|
|
62 extern char *monitor_dotclock_str;
|
|
63
|
|
64 static range_t *monitor_hfreq = NULL;
|
|
65 static range_t *monitor_vfreq = NULL;
|
|
66 static range_t *monitor_dotclock = NULL;
|
|
67
|
359
|
68 typedef struct {
|
|
69 char *name;
|
|
70 uint32_t xres, yres, vxres, vyres, depth;
|
|
71 uint32_t pixclock, left, right, upper, lower, hslen, vslen;
|
|
72 uint32_t sync;
|
|
73 uint32_t vmode;
|
|
74 } fb_mode_t;
|
|
75
|
|
76 #define PRINT_LINENUM printf(" at line %d\n", line_num)
|
|
77
|
|
78 #define MAX_NR_TOKEN 16
|
|
79
|
|
80 #define MAX_LINE_LEN 1000
|
|
81
|
|
82 #define RET_EOF -1
|
|
83 #define RET_EOL -2
|
|
84
|
|
85 static int validate_mode(fb_mode_t *m)
|
|
86 {
|
|
87 if (!m->xres) {
|
|
88 printf("needs geometry ");
|
|
89 return 0;
|
|
90 }
|
|
91 if (!m->pixclock) {
|
|
92 printf("needs timings ");
|
|
93 return 0;
|
|
94 }
|
|
95 return 1;
|
|
96 }
|
|
97
|
|
98 static FILE *fp;
|
|
99 static int line_num = 0;
|
|
100 static char *line;
|
|
101 static char *token[MAX_NR_TOKEN];
|
4756
|
102 static uint32_t dstFourcc;
|
359
|
103
|
|
104 static int get_token(int num)
|
|
105 {
|
|
106 static int read_nextline = 1;
|
|
107 static int line_pos;
|
|
108 int i;
|
|
109 char c;
|
|
110
|
|
111 if (num >= MAX_NR_TOKEN) {
|
|
112 printf("get_token(): max >= MAX_NR_TOKEN!");
|
|
113 goto out_eof;
|
|
114 }
|
|
115
|
|
116 if (read_nextline) {
|
|
117 if (!fgets(line, MAX_LINE_LEN, fp))
|
|
118 goto out_eof;
|
|
119 line_pos = 0;
|
|
120 ++line_num;
|
|
121 read_nextline = 0;
|
|
122 }
|
|
123 for (i = 0; i < num; i++) {
|
|
124 while (isspace(line[line_pos]))
|
|
125 ++line_pos;
|
|
126 if (line[line_pos] == '\0' || line[line_pos] == '#') {
|
|
127 read_nextline = 1;
|
|
128 goto out_eol;
|
|
129 }
|
|
130 token[i] = line + line_pos;
|
|
131 c = line[line_pos];
|
|
132 if (c == '"' || c == '\'') {
|
|
133 token[i]++;
|
|
134 while (line[++line_pos] != c && line[line_pos])
|
|
135 /* NOTHING */;
|
950
|
136 if (!line[line_pos])
|
|
137 goto out_eol;
|
|
138 line[line_pos] = ' ';
|
359
|
139 } else {
|
|
140 for (/* NOTHING */; !isspace(line[line_pos]) &&
|
|
141 line[line_pos]; line_pos++)
|
|
142 /* NOTHING */;
|
|
143 }
|
|
144 if (!line[line_pos]) {
|
|
145 read_nextline = 1;
|
|
146 if (i == num - 1)
|
|
147 goto out_ok;
|
|
148 goto out_eol;
|
|
149 }
|
950
|
150 line[line_pos++] = '\0';
|
359
|
151 }
|
|
152 out_ok:
|
|
153 return i;
|
|
154 out_eof:
|
|
155 return RET_EOF;
|
|
156 out_eol:
|
|
157 return RET_EOL;
|
|
158 }
|
|
159
|
|
160 static fb_mode_t *fb_modes = NULL;
|
|
161 static int nr_modes = 0;
|
|
162
|
|
163 static int parse_fbmode_cfg(char *cfgfile)
|
|
164 {
|
977
|
165 #define CHECK_IN_MODE_DEF\
|
|
166 do {\
|
|
167 if (!in_mode_def) {\
|
|
168 printf("'needs 'mode' first");\
|
|
169 goto err_out_print_linenum;\
|
|
170 }\
|
|
171 } while (0)
|
|
172
|
359
|
173 fb_mode_t *mode = NULL;
|
|
174 char *endptr; // strtoul()...
|
977
|
175 int in_mode_def = 0;
|
359
|
176 int tmp, i;
|
|
177
|
950
|
178 if (verbose > 0)
|
|
179 printf("Reading %s: ", cfgfile);
|
359
|
180
|
|
181 if ((fp = fopen(cfgfile, "r")) == NULL) {
|
|
182 printf("can't open '%s': %s\n", cfgfile, strerror(errno));
|
|
183 return -1;
|
|
184 }
|
|
185
|
|
186 if ((line = (char *) malloc(MAX_LINE_LEN + 1)) == NULL) {
|
|
187 printf("can't get memory for 'line': %s\n", strerror(errno));
|
|
188 return -2;
|
|
189 }
|
|
190
|
|
191 /*
|
|
192 * check if the cfgfile starts with 'mode'
|
|
193 */
|
|
194 while ((tmp = get_token(1)) == RET_EOL)
|
|
195 /* NOTHING */;
|
|
196 if (tmp == RET_EOF)
|
|
197 goto out;
|
|
198 if (!strcmp(token[0], "mode"))
|
|
199 goto loop_enter;
|
|
200 goto err_out_parse_error;
|
|
201
|
|
202 while ((tmp = get_token(1)) != RET_EOF) {
|
|
203 if (tmp == RET_EOL)
|
|
204 continue;
|
|
205 if (!strcmp(token[0], "mode")) {
|
977
|
206 if (in_mode_def) {
|
|
207 printf("'endmode' required");
|
|
208 goto err_out_print_linenum;
|
|
209 }
|
359
|
210 if (!validate_mode(mode))
|
|
211 goto err_out_not_valid;
|
|
212 loop_enter:
|
|
213 if (!(fb_modes = (fb_mode_t *) realloc(fb_modes,
|
|
214 sizeof(fb_mode_t) * (nr_modes + 1)))) {
|
950
|
215 printf("can't realloc 'fb_modes' (nr_modes = %d):"
|
|
216 " %s\n", nr_modes, strerror(errno));
|
359
|
217 goto err_out;
|
|
218 }
|
|
219 mode=fb_modes + nr_modes;
|
|
220 ++nr_modes;
|
|
221 memset(mode,0,sizeof(fb_mode_t));
|
225
|
222
|
359
|
223 if (get_token(1) < 0)
|
|
224 goto err_out_parse_error;
|
|
225 for (i = 0; i < nr_modes - 1; i++) {
|
|
226 if (!strcmp(token[0], fb_modes[i].name)) {
|
|
227 printf("mode name '%s' isn't unique", token[0]);
|
|
228 goto err_out_print_linenum;
|
|
229 }
|
|
230 }
|
|
231 if (!(mode->name = strdup(token[0]))) {
|
|
232 printf("can't strdup -> 'name': %s\n", strerror(errno));
|
|
233 goto err_out;
|
|
234 }
|
977
|
235 in_mode_def = 1;
|
359
|
236 } else if (!strcmp(token[0], "geometry")) {
|
977
|
237 CHECK_IN_MODE_DEF;
|
359
|
238 if (get_token(5) < 0)
|
|
239 goto err_out_parse_error;
|
|
240 mode->xres = strtoul(token[0], &endptr, 0);
|
|
241 if (*endptr)
|
|
242 goto err_out_parse_error;
|
|
243 mode->yres = strtoul(token[1], &endptr, 0);
|
|
244 if (*endptr)
|
|
245 goto err_out_parse_error;
|
|
246 mode->vxres = strtoul(token[2], &endptr, 0);
|
|
247 if (*endptr)
|
|
248 goto err_out_parse_error;
|
|
249 mode->vyres = strtoul(token[3], &endptr, 0);
|
|
250 if (*endptr)
|
|
251 goto err_out_parse_error;
|
|
252 mode->depth = strtoul(token[4], &endptr, 0);
|
|
253 if (*endptr)
|
|
254 goto err_out_parse_error;
|
|
255 } else if (!strcmp(token[0], "timings")) {
|
977
|
256 CHECK_IN_MODE_DEF;
|
359
|
257 if (get_token(7) < 0)
|
|
258 goto err_out_parse_error;
|
|
259 mode->pixclock = strtoul(token[0], &endptr, 0);
|
|
260 if (*endptr)
|
|
261 goto err_out_parse_error;
|
|
262 mode->left = strtoul(token[1], &endptr, 0);
|
|
263 if (*endptr)
|
|
264 goto err_out_parse_error;
|
|
265 mode->right = strtoul(token[2], &endptr, 0);
|
|
266 if (*endptr)
|
|
267 goto err_out_parse_error;
|
|
268 mode->upper = strtoul(token[3], &endptr, 0);
|
|
269 if (*endptr)
|
|
270 goto err_out_parse_error;
|
|
271 mode->lower = strtoul(token[4], &endptr, 0);
|
|
272 if (*endptr)
|
|
273 goto err_out_parse_error;
|
|
274 mode->hslen = strtoul(token[5], &endptr, 0);
|
|
275 if (*endptr)
|
|
276 goto err_out_parse_error;
|
|
277 mode->vslen = strtoul(token[6], &endptr, 0);
|
|
278 if (*endptr)
|
|
279 goto err_out_parse_error;
|
|
280 } else if (!strcmp(token[0], "endmode")) {
|
977
|
281 CHECK_IN_MODE_DEF;
|
|
282 in_mode_def = 0;
|
383
|
283 } else if (!strcmp(token[0], "accel")) {
|
977
|
284 CHECK_IN_MODE_DEF;
|
383
|
285 if (get_token(1) < 0)
|
|
286 goto err_out_parse_error;
|
393
|
287 /*
|
|
288 * it's only used for text acceleration
|
|
289 * so we just ignore it.
|
|
290 */
|
359
|
291 } else if (!strcmp(token[0], "hsync")) {
|
977
|
292 CHECK_IN_MODE_DEF;
|
359
|
293 if (get_token(1) < 0)
|
|
294 goto err_out_parse_error;
|
|
295 if (!strcmp(token[0], "low"))
|
|
296 mode->sync &= ~FB_SYNC_HOR_HIGH_ACT;
|
|
297 else if(!strcmp(token[0], "high"))
|
|
298 mode->sync |= FB_SYNC_HOR_HIGH_ACT;
|
|
299 else
|
|
300 goto err_out_parse_error;
|
|
301 } else if (!strcmp(token[0], "vsync")) {
|
977
|
302 CHECK_IN_MODE_DEF;
|
359
|
303 if (get_token(1) < 0)
|
|
304 goto err_out_parse_error;
|
|
305 if (!strcmp(token[0], "low"))
|
|
306 mode->sync &= ~FB_SYNC_VERT_HIGH_ACT;
|
|
307 else if(!strcmp(token[0], "high"))
|
|
308 mode->sync |= FB_SYNC_VERT_HIGH_ACT;
|
|
309 else
|
|
310 goto err_out_parse_error;
|
|
311 } else if (!strcmp(token[0], "csync")) {
|
977
|
312 CHECK_IN_MODE_DEF;
|
359
|
313 if (get_token(1) < 0)
|
|
314 goto err_out_parse_error;
|
|
315 if (!strcmp(token[0], "low"))
|
|
316 mode->sync &= ~FB_SYNC_COMP_HIGH_ACT;
|
|
317 else if(!strcmp(token[0], "high"))
|
|
318 mode->sync |= FB_SYNC_COMP_HIGH_ACT;
|
|
319 else
|
|
320 goto err_out_parse_error;
|
|
321 } else if (!strcmp(token[0], "extsync")) {
|
977
|
322 CHECK_IN_MODE_DEF;
|
359
|
323 if (get_token(1) < 0)
|
|
324 goto err_out_parse_error;
|
|
325 if (!strcmp(token[0], "false"))
|
|
326 mode->sync &= ~FB_SYNC_EXT;
|
|
327 else if(!strcmp(token[0], "true"))
|
|
328 mode->sync |= FB_SYNC_EXT;
|
|
329 else
|
|
330 goto err_out_parse_error;
|
|
331 } else if (!strcmp(token[0], "laced")) {
|
977
|
332 CHECK_IN_MODE_DEF;
|
359
|
333 if (get_token(1) < 0)
|
|
334 goto err_out_parse_error;
|
|
335 if (!strcmp(token[0], "false"))
|
|
336 mode->vmode = FB_VMODE_NONINTERLACED;
|
|
337 else if (!strcmp(token[0], "true"))
|
|
338 mode->vmode = FB_VMODE_INTERLACED;
|
|
339 else
|
|
340 goto err_out_parse_error;
|
479
|
341 } else if (!strcmp(token[0], "double")) {
|
977
|
342 CHECK_IN_MODE_DEF;
|
359
|
343 if (get_token(1) < 0)
|
|
344 goto err_out_parse_error;
|
|
345 if (!strcmp(token[0], "false"))
|
|
346 ;
|
|
347 else if (!strcmp(token[0], "true"))
|
|
348 mode->vmode = FB_VMODE_DOUBLE;
|
|
349 else
|
|
350 goto err_out_parse_error;
|
|
351 } else
|
|
352 goto err_out_parse_error;
|
|
353 }
|
|
354 if (!validate_mode(mode))
|
|
355 goto err_out_not_valid;
|
|
356 out:
|
950
|
357 if (verbose > 0)
|
|
358 printf("%d modes\n", nr_modes);
|
359
|
359 free(line);
|
|
360 fclose(fp);
|
|
361 return nr_modes;
|
|
362 err_out_parse_error:
|
|
363 printf("parse error");
|
|
364 err_out_print_linenum:
|
|
365 PRINT_LINENUM;
|
|
366 err_out:
|
393
|
367 if (fb_modes) {
|
359
|
368 free(fb_modes);
|
393
|
369 fb_modes = NULL;
|
|
370 }
|
|
371 nr_modes = 0;
|
359
|
372 free(line);
|
|
373 free(fp);
|
|
374 return -2;
|
|
375 err_out_not_valid:
|
950
|
376 printf("previous mode is not correct");
|
359
|
377 goto err_out_print_linenum;
|
|
378 }
|
|
379
|
|
380 static fb_mode_t *find_mode_by_name(char *name)
|
|
381 {
|
|
382 int i;
|
|
383
|
658
|
384 for (i = 0; i < nr_modes; i++)
|
359
|
385 if (!strcmp(name, fb_modes[i].name))
|
|
386 return fb_modes + i;
|
|
387 return NULL;
|
|
388 }
|
|
389
|
393
|
390 static float dcf(fb_mode_t *m) //driving clock frequency
|
|
391 {
|
519
|
392 return 1e12f / m->pixclock;
|
393
|
393 }
|
|
394
|
|
395 static float hsf(fb_mode_t *m) //horizontal scan frequency
|
|
396 {
|
|
397 int htotal = m->left + m->xres + m->right + m->hslen;
|
|
398 return dcf(m) / htotal;
|
|
399 }
|
|
400
|
|
401 static float vsf(fb_mode_t *m) //vertical scan frequency
|
|
402 {
|
|
403 int vtotal = m->upper + m->yres + m->lower + m->vslen;
|
|
404 return hsf(m) / vtotal;
|
|
405 }
|
|
406
|
|
407
|
1561
|
408 static int mode_works(fb_mode_t *m, range_t *hfreq, range_t *vfreq,
|
|
409 range_t *dotclock)
|
|
410 {
|
|
411 float h = hsf(m);
|
|
412 float v = vsf(m);
|
|
413 float d = dcf(m);
|
|
414 int ret = 1;
|
|
415
|
|
416 if (verbose > 1)
|
|
417 printf(FBDEV "mode %dx%d:", m->xres, m->yres);
|
|
418 if (!in_range(hfreq, h)) {
|
|
419 ret = 0;
|
|
420 if (verbose > 1)
|
|
421 printf(" hsync out of range.");
|
|
422 }
|
|
423 if (!in_range(vfreq, v)) {
|
|
424 ret = 0;
|
|
425 if (verbose > 1)
|
|
426 printf(" vsync out of range.");
|
|
427 }
|
|
428 if (!in_range(dotclock, d)) {
|
|
429 ret = 0;
|
|
430 if (verbose > 1)
|
|
431 printf(" dotclock out of range.");
|
|
432 }
|
|
433 if (verbose > 1) {
|
|
434 if (ret)
|
|
435 printf(" hsync, vsync, dotclock ok.\n");
|
|
436 else
|
|
437 printf("\n");
|
|
438 }
|
|
439
|
|
440 return ret;
|
|
441 }
|
|
442
|
418
|
443 static fb_mode_t *find_best_mode(int xres, int yres, range_t *hfreq,
|
|
444 range_t *vfreq, range_t *dotclock)
|
393
|
445 {
|
|
446 int i;
|
|
447 fb_mode_t *best = fb_modes;
|
519
|
448 fb_mode_t *curr;
|
|
449
|
1561
|
450 if (verbose > 1)
|
|
451 printf(FBDEV "Searching for first working mode\n");
|
|
452
|
950
|
453 for (i = 0; i < nr_modes; i++, best++)
|
1561
|
454 if (mode_works(best, hfreq, vfreq, dotclock))
|
519
|
455 break;
|
|
456
|
950
|
457 if (i == nr_modes)
|
519
|
458 return NULL;
|
950
|
459 if (i == nr_modes - 1)
|
519
|
460 return best;
|
393
|
461
|
1561
|
462 if (verbose > 1) {
|
|
463 printf(FBDEV "First working mode: %dx%d\n", best->xres, best->yres);
|
|
464 printf(FBDEV "Searching for better modes\n");
|
|
465 }
|
950
|
466
|
1561
|
467 for (curr = best + 1; i < nr_modes - 1; i++, curr++) {
|
|
468 if (!mode_works(curr, hfreq, vfreq, dotclock))
|
519
|
469 continue;
|
1561
|
470
|
519
|
471 if (verbose > 1)
|
1561
|
472 printf(FBDEV);
|
|
473
|
|
474 if (best->xres < xres || best->yres < yres) {
|
|
475 if (curr->xres > best->xres || curr->yres > best->yres) {
|
519
|
476 if (verbose > 1)
|
1561
|
477 printf("better than %dx%d, which is too small.\n",
|
519
|
478 best->xres, best->yres);
|
393
|
479 best = curr;
|
519
|
480 } else if (verbose > 1)
|
1561
|
481 printf("too small.\n");
|
|
482 } else if (curr->xres == best->xres && curr->yres == best->yres &&
|
|
483 vsf(curr) > vsf(best)) {
|
|
484 if (verbose > 1)
|
|
485 printf("faster screen refresh.\n");
|
|
486 best = curr;
|
|
487 } else if ((curr->xres <= best->xres && curr->yres <= best->yres) &&
|
|
488 (curr->xres >= xres && curr->yres >= yres)) {
|
|
489 if (verbose > 1)
|
|
490 printf("better than %dx%d, which is too large.\n",
|
|
491 best->xres, best->yres);
|
|
492 best = curr;
|
|
493 } else if (verbose > 1) {
|
|
494 if (curr->xres < xres || curr->yres < yres)
|
|
495 printf("too small.\n");
|
|
496 else if (curr->xres > best->xres || curr->yres > best->yres)
|
|
497 printf("too large.\n");
|
|
498 else printf("it's worse, don't know why.\n");
|
|
499 }
|
393
|
500 }
|
1561
|
501
|
393
|
502 return best;
|
|
503 }
|
|
504
|
418
|
505 static void set_bpp(struct fb_var_screeninfo *p, int bpp)
|
|
506 {
|
476
|
507 p->bits_per_pixel = (bpp + 1) & ~1;
|
1087
|
508 p->red.msb_right = p->green.msb_right = p->blue.msb_right = p->transp.msb_right = 0;
|
563
|
509 p->transp.offset = p->transp.length = 0;
|
950
|
510 p->blue.offset = 0;
|
418
|
511 switch (bpp) {
|
|
512 case 32:
|
563
|
513 p->transp.offset = 24;
|
|
514 p->transp.length = 8;
|
418
|
515 case 24:
|
|
516 p->red.offset = 16;
|
|
517 p->red.length = 8;
|
|
518 p->green.offset = 8;
|
|
519 p->green.length = 8;
|
550
|
520 p->blue.length = 8;
|
418
|
521 break;
|
|
522 case 16:
|
|
523 p->red.offset = 11;
|
550
|
524 p->green.length = 6;
|
418
|
525 p->red.length = 5;
|
|
526 p->green.offset = 5;
|
550
|
527 p->blue.length = 5;
|
418
|
528 break;
|
|
529 case 15:
|
|
530 p->red.offset = 10;
|
550
|
531 p->green.length = 5;
|
418
|
532 p->red.length = 5;
|
|
533 p->green.offset = 5;
|
550
|
534 p->blue.length = 5;
|
418
|
535 break;
|
|
536 }
|
|
537 }
|
|
538
|
|
539 static void fb_mode2fb_vinfo(fb_mode_t *m, struct fb_var_screeninfo *v)
|
|
540 {
|
|
541 v->xres = m->xres;
|
|
542 v->yres = m->yres;
|
|
543 v->xres_virtual = m->vxres;
|
|
544 v->yres_virtual = m->vyres;
|
|
545 set_bpp(v, m->depth);
|
|
546 v->pixclock = m->pixclock;
|
|
547 v->left_margin = m->left;
|
|
548 v->right_margin = m->right;
|
|
549 v->upper_margin = m->upper;
|
|
550 v->lower_margin = m->lower;
|
|
551 v->hsync_len = m->hslen;
|
|
552 v->vsync_len = m->vslen;
|
|
553 v->sync = m->sync;
|
|
554 v->vmode = m->vmode;
|
|
555 }
|
|
556
|
|
557
|
359
|
558 /******************************
|
|
559 * vo_fbdev *
|
|
560 ******************************/
|
|
561
|
658
|
562 /* command line/config file options */
|
393
|
563 char *fb_dev_name = NULL;
|
|
564 char *fb_mode_cfgfile = "/etc/fb.modes";
|
|
565 char *fb_mode_name = NULL;
|
418
|
566
|
658
|
567 static fb_mode_t *fb_mode = NULL;
|
393
|
568
|
950
|
569 /* vt related variables */
|
1087
|
570 static int vt_fd;
|
|
571 static FILE *vt_fp;
|
|
572 static int vt_doit = 1;
|
950
|
573
|
658
|
574 /* vo_fbdev related variables */
|
225
|
575 static int fb_dev_fd;
|
2354
|
576 static int fb_tty_fd;
|
225
|
577 static size_t fb_size;
|
|
578 static uint8_t *frame_buffer;
|
658
|
579 static uint8_t *L123123875; /* thx .so :) */
|
359
|
580 static struct fb_fix_screeninfo fb_finfo;
|
|
581 static struct fb_var_screeninfo fb_orig_vinfo;
|
|
582 static struct fb_var_screeninfo fb_vinfo;
|
481
|
583 static struct fb_cmap fb_oldcmap;
|
|
584 static int fb_cmap_changed = 0;
|
359
|
585 static int fb_pixel_size; // 32: 4 24: 3 16: 2 15: 2
|
|
586 static int fb_real_bpp; // 32: 24 24: 24 16: 16 15: 15
|
|
587 static int fb_bpp; // 32: 32 24: 24 16: 16 15: 15
|
393
|
588 static int fb_bpp_we_want; // 32: 32 24: 24 16: 16 15: 15
|
950
|
589 static int fb_line_len;
|
|
590 static int fb_xres;
|
|
591 static int fb_yres;
|
658
|
592 static void (*draw_alpha_p)(int w, int h, unsigned char *src,
|
|
593 unsigned char *srca, int stride, unsigned char *dst,
|
|
594 int dstride);
|
359
|
595
|
|
596 static uint8_t *next_frame;
|
225
|
597 static int in_width;
|
|
598 static int in_height;
|
|
599 static int out_width;
|
|
600 static int out_height;
|
950
|
601 static int first_row;
|
|
602 static int last_row;
|
225
|
603 static uint32_t pixel_format;
|
804
|
604 static int fs;
|
|
605 static int flip;
|
225
|
606
|
305
|
607 /*
|
|
608 * Note: this function is completely cut'n'pasted from
|
|
609 * Chris Lawrence's code.
|
311
|
610 * (modified a bit to fit in my code...)
|
305
|
611 */
|
|
612 struct fb_cmap *make_directcolor_cmap(struct fb_var_screeninfo *var)
|
|
613 {
|
|
614 /* Hopefully any DIRECTCOLOR device will have a big enough palette
|
|
615 * to handle mapping the full color depth.
|
|
616 * e.g. 8 bpp -> 256 entry palette
|
|
617 *
|
|
618 * We could handle some sort of gamma here
|
|
619 */
|
|
620 int i, cols, rcols, gcols, bcols;
|
|
621 uint16_t *red, *green, *blue;
|
|
622 struct fb_cmap *cmap;
|
|
623
|
|
624 rcols = 1 << var->red.length;
|
|
625 gcols = 1 << var->green.length;
|
|
626 bcols = 1 << var->blue.length;
|
|
627
|
|
628 /* Make our palette the length of the deepest color */
|
|
629 cols = (rcols > gcols ? rcols : gcols);
|
|
630 cols = (cols > bcols ? cols : bcols);
|
|
631
|
|
632 red = malloc(cols * sizeof(red[0]));
|
|
633 if(!red) {
|
|
634 printf("Can't allocate red palette with %d entries.\n", cols);
|
|
635 return NULL;
|
|
636 }
|
|
637 for(i=0; i< rcols; i++)
|
|
638 red[i] = (65535/(rcols-1)) * i;
|
|
639
|
|
640 green = malloc(cols * sizeof(green[0]));
|
|
641 if(!green) {
|
|
642 printf("Can't allocate green palette with %d entries.\n", cols);
|
|
643 free(red);
|
|
644 return NULL;
|
|
645 }
|
|
646 for(i=0; i< gcols; i++)
|
|
647 green[i] = (65535/(gcols-1)) * i;
|
|
648
|
|
649 blue = malloc(cols * sizeof(blue[0]));
|
|
650 if(!blue) {
|
|
651 printf("Can't allocate blue palette with %d entries.\n", cols);
|
|
652 free(red);
|
|
653 free(green);
|
|
654 return NULL;
|
|
655 }
|
|
656 for(i=0; i< bcols; i++)
|
|
657 blue[i] = (65535/(bcols-1)) * i;
|
|
658
|
|
659 cmap = malloc(sizeof(struct fb_cmap));
|
|
660 if(!cmap) {
|
|
661 printf("Can't allocate color map\n");
|
|
662 free(red);
|
|
663 free(green);
|
|
664 free(blue);
|
|
665 return NULL;
|
|
666 }
|
|
667 cmap->start = 0;
|
|
668 cmap->transp = 0;
|
|
669 cmap->len = cols;
|
|
670 cmap->red = red;
|
|
671 cmap->blue = blue;
|
|
672 cmap->green = green;
|
|
673 cmap->transp = NULL;
|
|
674
|
|
675 return cmap;
|
|
676 }
|
225
|
677
|
4089
|
678 #ifdef CONFIG_VIDIX
|
4084
|
679 static uint32_t parseSubDevice(const char *sd)
|
|
680 {
|
|
681 if(memcmp(sd,"vidix",5) == 0) vidix_name = &sd[5]; /* vidix_name will be valid within init() */
|
|
682 else { printf(FBDEV "Unknown subdevice: '%s'\n", sd); return -1; }
|
|
683 return 0;
|
|
684 }
|
4089
|
685 #endif
|
4084
|
686
|
393
|
687 static int fb_preinit(void)
|
225
|
688 {
|
950
|
689 static int fb_preinit_done = 0;
|
|
690 static int fb_works = 0;
|
|
691
|
|
692 if (fb_preinit_done)
|
|
693 return fb_works;
|
|
694
|
393
|
695 if (!fb_dev_name && !(fb_dev_name = getenv("FRAMEBUFFER")))
|
|
696 fb_dev_name = "/dev/fb0";
|
|
697 if (verbose > 0)
|
|
698 printf(FBDEV "using %s\n", fb_dev_name);
|
225
|
699
|
393
|
700 if ((fb_dev_fd = open(fb_dev_name, O_RDWR)) == -1) {
|
|
701 printf(FBDEV "Can't open %s: %s\n", fb_dev_name, strerror(errno));
|
|
702 goto err_out;
|
|
703 }
|
|
704 if (ioctl(fb_dev_fd, FBIOGET_VSCREENINFO, &fb_vinfo)) {
|
|
705 printf(FBDEV "Can't get VSCREENINFO: %s\n", strerror(errno));
|
|
706 goto err_out_fd;
|
|
707 }
|
418
|
708 fb_orig_vinfo = fb_vinfo;
|
393
|
709
|
2354
|
710 if ((fb_tty_fd = open("/dev/tty", O_RDWR)) < 0) {
|
|
711 if (verbose > 0)
|
|
712 printf(FBDEV "notice: Can't open /dev/tty: %s\n", strerror(errno));
|
|
713 }
|
|
714
|
663
|
715 fb_bpp = fb_vinfo.bits_per_pixel;
|
|
716
|
1076
|
717 if (fb_bpp == 8 && !vo_dbpp) {
|
|
718 printf(FBDEV "8 bpp output is not supported.\n");
|
2354
|
719 goto err_out_tty_fd;
|
1076
|
720 }
|
|
721
|
1561
|
722 /* 16 and 15 bpp is reported as 16 bpp */
|
663
|
723 if (fb_bpp == 16)
|
|
724 fb_bpp = fb_vinfo.red.length + fb_vinfo.green.length +
|
|
725 fb_vinfo.blue.length;
|
|
726
|
418
|
727 if (vo_dbpp) {
|
|
728 if (vo_dbpp != 15 && vo_dbpp != 16 && vo_dbpp != 24 &&
|
|
729 vo_dbpp != 32) {
|
|
730 printf(FBDEV "can't switch to %d bpp\n", vo_dbpp);
|
1076
|
731 goto err_out_fd;
|
359
|
732 }
|
418
|
733 fb_bpp = vo_dbpp;
|
359
|
734 }
|
245
|
735
|
393
|
736 fb_preinit_done = 1;
|
|
737 fb_works = 1;
|
950
|
738 return 1;
|
2354
|
739 err_out_tty_fd:
|
|
740 close(fb_tty_fd);
|
|
741 fb_tty_fd = -1;
|
393
|
742 err_out_fd:
|
|
743 close(fb_dev_fd);
|
|
744 fb_dev_fd = -1;
|
|
745 err_out:
|
|
746 fb_preinit_done = 1;
|
950
|
747 fb_works = 0;
|
|
748 return 0;
|
393
|
749 }
|
245
|
750
|
633
|
751 static void lots_of_printf(void)
|
|
752 {
|
|
753 if (verbose > 0) {
|
|
754 printf(FBDEV "var info:\n");
|
|
755 printf(FBDEV "xres: %u\n", fb_vinfo.xres);
|
|
756 printf(FBDEV "yres: %u\n", fb_vinfo.yres);
|
|
757 printf(FBDEV "xres_virtual: %u\n", fb_vinfo.xres_virtual);
|
|
758 printf(FBDEV "yres_virtual: %u\n", fb_vinfo.yres_virtual);
|
|
759 printf(FBDEV "xoffset: %u\n", fb_vinfo.xoffset);
|
|
760 printf(FBDEV "yoffset: %u\n", fb_vinfo.yoffset);
|
|
761 printf(FBDEV "bits_per_pixel: %u\n", fb_vinfo.bits_per_pixel);
|
|
762 printf(FBDEV "grayscale: %u\n", fb_vinfo.grayscale);
|
|
763 printf(FBDEV "red: %lu %lu %lu\n",
|
|
764 (unsigned long) fb_vinfo.red.offset,
|
|
765 (unsigned long) fb_vinfo.red.length,
|
|
766 (unsigned long) fb_vinfo.red.msb_right);
|
|
767 printf(FBDEV "green: %lu %lu %lu\n",
|
|
768 (unsigned long) fb_vinfo.green.offset,
|
|
769 (unsigned long) fb_vinfo.green.length,
|
|
770 (unsigned long) fb_vinfo.green.msb_right);
|
|
771 printf(FBDEV "blue: %lu %lu %lu\n",
|
|
772 (unsigned long) fb_vinfo.blue.offset,
|
|
773 (unsigned long) fb_vinfo.blue.length,
|
|
774 (unsigned long) fb_vinfo.blue.msb_right);
|
|
775 printf(FBDEV "transp: %lu %lu %lu\n",
|
|
776 (unsigned long) fb_vinfo.transp.offset,
|
|
777 (unsigned long) fb_vinfo.transp.length,
|
|
778 (unsigned long) fb_vinfo.transp.msb_right);
|
|
779 printf(FBDEV "nonstd: %u\n", fb_vinfo.nonstd);
|
|
780 if (verbose > 1) {
|
|
781 printf(FBDEV "activate: %u\n", fb_vinfo.activate);
|
|
782 printf(FBDEV "height: %u\n", fb_vinfo.height);
|
|
783 printf(FBDEV "width: %u\n", fb_vinfo.width);
|
|
784 printf(FBDEV "accel_flags: %u\n", fb_vinfo.accel_flags);
|
|
785 printf(FBDEV "timing:\n");
|
|
786 printf(FBDEV "pixclock: %u\n", fb_vinfo.pixclock);
|
|
787 printf(FBDEV "left_margin: %u\n", fb_vinfo.left_margin);
|
|
788 printf(FBDEV "right_margin: %u\n", fb_vinfo.right_margin);
|
|
789 printf(FBDEV "upper_margin: %u\n", fb_vinfo.upper_margin);
|
|
790 printf(FBDEV "lower_margin: %u\n", fb_vinfo.lower_margin);
|
|
791 printf(FBDEV "hsync_len: %u\n", fb_vinfo.hsync_len);
|
|
792 printf(FBDEV "vsync_len: %u\n", fb_vinfo.vsync_len);
|
|
793 printf(FBDEV "sync: %u\n", fb_vinfo.sync);
|
|
794 printf(FBDEV "vmode: %u\n", fb_vinfo.vmode);
|
|
795 }
|
|
796 printf(FBDEV "fix info:\n");
|
|
797 printf(FBDEV "framebuffer size: %d bytes\n", fb_finfo.smem_len);
|
|
798 printf(FBDEV "type: %lu\n", (unsigned long) fb_finfo.type);
|
|
799 printf(FBDEV "type_aux: %lu\n", (unsigned long) fb_finfo.type_aux);
|
|
800 printf(FBDEV "visual: %lu\n", (unsigned long) fb_finfo.visual);
|
|
801 printf(FBDEV "line_length: %lu bytes\n", (unsigned long) fb_finfo.line_length);
|
|
802 if (verbose > 1) {
|
|
803 printf(FBDEV "id: %.16s\n", fb_finfo.id);
|
|
804 printf(FBDEV "smem_start: %p\n", (void *) fb_finfo.smem_start);
|
|
805 printf(FBDEV "xpanstep: %u\n", fb_finfo.xpanstep);
|
|
806 printf(FBDEV "ypanstep: %u\n", fb_finfo.ypanstep);
|
|
807 printf(FBDEV "ywrapstep: %u\n", fb_finfo.ywrapstep);
|
|
808 printf(FBDEV "mmio_start: %p\n", (void *) fb_finfo.mmio_start);
|
|
809 printf(FBDEV "mmio_len: %u bytes\n", fb_finfo.mmio_len);
|
|
810 printf(FBDEV "accel: %u\n", fb_finfo.accel);
|
|
811 }
|
950
|
812 printf(FBDEV "fb_bpp: %d\n", fb_bpp);
|
|
813 printf(FBDEV "fb_real_bpp: %d\n", fb_real_bpp);
|
|
814 printf(FBDEV "fb_pixel_size: %d bytes\n", fb_pixel_size);
|
|
815 printf(FBDEV "other:\n");
|
|
816 printf(FBDEV "in_width: %d\n", in_width);
|
|
817 printf(FBDEV "in_height: %d\n", in_height);
|
|
818 printf(FBDEV "out_width: %d\n", out_width);
|
|
819 printf(FBDEV "out_height: %d\n", out_height);
|
|
820 printf(FBDEV "first_row: %d\n", first_row);
|
|
821 printf(FBDEV "last_row: %d\n", last_row);
|
|
822 if (verbose > 1)
|
|
823 printf(FBDEV "draw_alpha_p:%dbpp = %p\n", fb_bpp, draw_alpha_p);
|
633
|
824 }
|
|
825 }
|
658
|
826
|
950
|
827 static void vt_set_textarea(int u, int l)
|
|
828 {
|
|
829 /* how can I determine the font height?
|
|
830 * just use 16 for now
|
|
831 */
|
|
832 int urow = ((u + 15) / 16) + 1;
|
|
833 int lrow = l / 16;
|
|
834
|
|
835 if (verbose > 1)
|
|
836 printf(FBDEV "vt_set_textarea(%d,%d): %d,%d\n", u, l, urow, lrow);
|
|
837 fprintf(vt_fp, "\33[%d;%dr\33[%d;%dH", urow, lrow, lrow, 0);
|
|
838 fflush(vt_fp);
|
|
839 }
|
|
840
|
4433
|
841 static uint32_t config(uint32_t width, uint32_t height, uint32_t d_width,
|
6851
|
842 uint32_t d_height, uint32_t flags, char *title,
|
7124
|
843 uint32_t format)
|
393
|
844 {
|
950
|
845 struct fb_cmap *cmap;
|
6851
|
846 int vm = flags & 0x02;
|
|
847 int zoom = flags & 0x04;
|
418
|
848
|
6851
|
849 fs = flags & 0x01;
|
|
850 flip = flags & 0x08;
|
393
|
851
|
6164
|
852 if(pre_init_err == -2)
|
4380
|
853 {
|
|
854 printf(FBDEV "Internal fatal error: init() was called before preinit()\n");
|
|
855 return -1;
|
|
856 }
|
|
857
|
|
858 if (pre_init_err) return 1;
|
245
|
859
|
7427
|
860 #if 0
|
4089
|
861 if (zoom
|
|
862 #ifdef CONFIG_VIDIX
|
|
863 && !vidix_name
|
|
864 #endif
|
|
865 ) {
|
418
|
866 printf(FBDEV "-zoom is not supported\n");
|
|
867 return 1;
|
|
868 }
|
7427
|
869 #endif
|
950
|
870 if (fb_mode_name && !vm) {
|
|
871 printf(FBDEV "-fbmode can only be used with -vm\n");
|
418
|
872 return 1;
|
|
873 }
|
950
|
874 if (vm && (parse_fbmode_cfg(fb_mode_cfgfile) < 0))
|
418
|
875 return 1;
|
950
|
876 if (d_width && (fs || vm)) {
|
418
|
877 out_width = d_width;
|
|
878 out_height = d_height;
|
|
879 } else {
|
|
880 out_width = width;
|
|
881 out_height = height;
|
|
882 }
|
|
883 in_width = width;
|
|
884 in_height = height;
|
|
885 pixel_format = format;
|
|
886
|
393
|
887 if (fb_mode_name) {
|
418
|
888 if (!(fb_mode = find_mode_by_name(fb_mode_name))) {
|
|
889 printf(FBDEV "can't find requested video mode\n");
|
|
890 return 1;
|
|
891 }
|
|
892 fb_mode2fb_vinfo(fb_mode, &fb_vinfo);
|
950
|
893 } else if (vm) {
|
418
|
894 monitor_hfreq = str2range(monitor_hfreq_str);
|
|
895 monitor_vfreq = str2range(monitor_vfreq_str);
|
|
896 monitor_dotclock = str2range(monitor_dotclock_str);
|
|
897 if (!monitor_hfreq || !monitor_vfreq || !monitor_dotclock) {
|
|
898 printf(FBDEV "you have to specify the capabilities of"
|
|
899 " the monitor.\n");
|
|
900 return 1;
|
|
901 }
|
|
902 if (!(fb_mode = find_best_mode(out_width, out_height,
|
|
903 monitor_hfreq, monitor_vfreq,
|
|
904 monitor_dotclock))) {
|
|
905 printf(FBDEV "can't find best video mode\n");
|
|
906 return 1;
|
|
907 }
|
519
|
908 printf(FBDEV "using mode %dx%d @ %.1fHz\n", fb_mode->xres,
|
|
909 fb_mode->yres, vsf(fb_mode));
|
418
|
910 fb_mode2fb_vinfo(fb_mode, &fb_vinfo);
|
359
|
911 }
|
418
|
912 fb_bpp_we_want = fb_bpp;
|
|
913 set_bpp(&fb_vinfo, fb_bpp);
|
359
|
914 fb_vinfo.xres_virtual = fb_vinfo.xres;
|
|
915 fb_vinfo.yres_virtual = fb_vinfo.yres;
|
245
|
916
|
2354
|
917 if (fb_tty_fd >= 0 && ioctl(fb_tty_fd, KDSETMODE, KD_GRAPHICS) < 0) {
|
|
918 if (verbose > 0)
|
|
919 printf(FBDEV "Can't set graphics mode: %s\n", strerror(errno));
|
|
920 close(fb_tty_fd);
|
|
921 fb_tty_fd = -1;
|
|
922 }
|
|
923
|
359
|
924 if (ioctl(fb_dev_fd, FBIOPUT_VSCREENINFO, &fb_vinfo)) {
|
393
|
925 printf(FBDEV "Can't put VSCREENINFO: %s\n", strerror(errno));
|
2354
|
926 if (fb_tty_fd >= 0 && ioctl(fb_tty_fd, KDSETMODE, KD_TEXT) < 0) {
|
|
927 printf(FBDEV "Can't restore text mode: %s\n", strerror(errno));
|
|
928 }
|
393
|
929 return 1;
|
|
930 }
|
950
|
931
|
|
932 fb_pixel_size = fb_vinfo.bits_per_pixel / 8;
|
|
933 fb_real_bpp = fb_vinfo.red.length + fb_vinfo.green.length +
|
|
934 fb_vinfo.blue.length;
|
|
935 fb_bpp = (fb_pixel_size == 4) ? 32 : fb_real_bpp;
|
|
936 if (fb_bpp_we_want != fb_bpp)
|
1076
|
937 printf(FBDEV "requested %d bpp, got %d bpp!!!\n",
|
950
|
938 fb_bpp_we_want, fb_bpp);
|
|
939
|
|
940 switch (fb_bpp) {
|
|
941 case 32:
|
|
942 draw_alpha_p = vo_draw_alpha_rgb32;
|
4756
|
943 dstFourcc = IMGFMT_BGR32;
|
950
|
944 break;
|
|
945 case 24:
|
|
946 draw_alpha_p = vo_draw_alpha_rgb24;
|
4756
|
947 dstFourcc = IMGFMT_BGR24;
|
950
|
948 break;
|
4756
|
949 default:
|
950
|
950 case 16:
|
|
951 draw_alpha_p = vo_draw_alpha_rgb16;
|
4756
|
952 dstFourcc = IMGFMT_BGR16;
|
950
|
953 break;
|
|
954 case 15:
|
|
955 draw_alpha_p = vo_draw_alpha_rgb15;
|
4756
|
956 dstFourcc = IMGFMT_BGR15;
|
950
|
957 break;
|
|
958 }
|
|
959
|
|
960 if (flip & ((((pixel_format & 0xff) + 7) / 8) != fb_pixel_size)) {
|
|
961 printf(FBDEV "Flipped output with depth conversion is not "
|
|
962 "supported\n");
|
|
963 return 1;
|
|
964 }
|
|
965
|
|
966 fb_xres = fb_vinfo.xres;
|
|
967 fb_yres = fb_vinfo.yres;
|
|
968
|
|
969 if (vm || fs) {
|
|
970 out_width = fb_xres;
|
|
971 out_height = fb_yres;
|
|
972 }
|
|
973 if (out_width < in_width || out_height < in_height) {
|
|
974 printf(FBDEV "screensize is smaller than video size\n");
|
|
975 return 1;
|
|
976 }
|
|
977
|
|
978 first_row = (out_height - in_height) / 2;
|
|
979 last_row = (out_height + in_height) / 2;
|
|
980
|
618
|
981 if (ioctl(fb_dev_fd, FBIOGET_FSCREENINFO, &fb_finfo)) {
|
|
982 printf(FBDEV "Can't get FSCREENINFO: %s\n", strerror(errno));
|
|
983 return 1;
|
|
984 }
|
633
|
985
|
|
986 lots_of_printf();
|
245
|
987
|
633
|
988 if (fb_finfo.type != FB_TYPE_PACKED_PIXELS) {
|
|
989 printf(FBDEV "type %d not supported\n", fb_finfo.type);
|
|
990 return 1;
|
305
|
991 }
|
618
|
992
|
379
|
993 switch (fb_finfo.visual) {
|
393
|
994 case FB_VISUAL_TRUECOLOR:
|
|
995 break;
|
|
996 case FB_VISUAL_DIRECTCOLOR:
|
|
997 if (verbose > 0)
|
|
998 printf(FBDEV "creating cmap for directcolor\n");
|
481
|
999 if (ioctl(fb_dev_fd, FBIOGETCMAP, &fb_oldcmap)) {
|
393
|
1000 printf(FBDEV "can't get cmap: %s\n",
|
|
1001 strerror(errno));
|
|
1002 return 1;
|
|
1003 }
|
|
1004 if (!(cmap = make_directcolor_cmap(&fb_vinfo)))
|
|
1005 return 1;
|
|
1006 if (ioctl(fb_dev_fd, FBIOPUTCMAP, cmap)) {
|
|
1007 printf(FBDEV "can't put cmap: %s\n",
|
|
1008 strerror(errno));
|
|
1009 return 1;
|
|
1010 }
|
481
|
1011 fb_cmap_changed = 1;
|
393
|
1012 free(cmap->red);
|
|
1013 free(cmap->green);
|
|
1014 free(cmap->blue);
|
|
1015 free(cmap);
|
|
1016 break;
|
|
1017 default:
|
|
1018 printf(FBDEV "visual: %d not yet supported\n",
|
|
1019 fb_finfo.visual);
|
|
1020 return 1;
|
245
|
1021 }
|
618
|
1022
|
950
|
1023 fb_line_len = fb_finfo.line_length;
|
359
|
1024 fb_size = fb_finfo.smem_len;
|
4084
|
1025 frame_buffer = NULL;
|
|
1026 next_frame = NULL;
|
4089
|
1027 #ifdef CONFIG_VIDIX
|
4084
|
1028 if(vidix_name)
|
|
1029 {
|
|
1030 unsigned image_width,image_height,x_offset,y_offset;
|
6851
|
1031 if(zoom || fs){
|
|
1032 aspect_save_orig(width,height);
|
|
1033 aspect_save_prescale(d_width,d_height);
|
|
1034 aspect_save_screenres(fb_xres,fb_yres);
|
|
1035 aspect(&image_width,&image_height,fs ? A_ZOOM : A_NOZOOM);
|
|
1036 } else {
|
4084
|
1037 image_width=width;
|
|
1038 image_height=height;
|
6851
|
1039 }
|
7875
|
1040 geometry(&x_offset,&y_offset,fb_xres,fb_yres,image_width,image_height,fs);
|
7866
|
1041
|
4084
|
1042 if(vidix_init(width,height,x_offset,y_offset,image_width,
|
|
1043 image_height,format,fb_bpp,
|
7124
|
1044 fb_xres,fb_yres) != 0)
|
4084
|
1045 {
|
|
1046 printf(FBDEV "Can't initialize VIDIX driver\n");
|
|
1047 vidix_name = NULL;
|
|
1048 vidix_term();
|
|
1049 return -1;
|
|
1050 }
|
|
1051 else printf(FBDEV "Using VIDIX\n");
|
4198
|
1052 vidix_start();
|
4084
|
1053 }
|
|
1054 else
|
4089
|
1055 #endif
|
4084
|
1056 {
|
7866
|
1057 int x_offset,y_offset;
|
4084
|
1058 if ((frame_buffer = (uint8_t *) mmap(0, fb_size, PROT_READ | PROT_WRITE,
|
|
1059 MAP_SHARED, fb_dev_fd, 0)) == (uint8_t *) -1) {
|
393
|
1060 printf(FBDEV "Can't mmap %s: %s\n", fb_dev_name, strerror(errno));
|
|
1061 return 1;
|
4084
|
1062 }
|
7866
|
1063
|
7875
|
1064 geometry(&x_offset,&y_offset,fb_xres,fb_yres,out_width,out_height,fs);
|
7866
|
1065
|
4084
|
1066 L123123875 = frame_buffer + (out_width - in_width) * fb_pixel_size /
|
7866
|
1067 2 + ( (out_height - in_height) / 2 ) * fb_line_len +
|
|
1068 x_offset * fb_pixel_size + y_offset * fb_line_len;
|
229
|
1069
|
4084
|
1070 if (verbose > 0) {
|
519
|
1071 if (verbose > 1) {
|
393
|
1072 printf(FBDEV "frame_buffer @ %p\n", frame_buffer);
|
519
|
1073 printf(FBDEV "L123123875 @ %p\n", L123123875);
|
|
1074 }
|
950
|
1075 printf(FBDEV "pixel per line: %d\n", fb_line_len / fb_pixel_size);
|
4084
|
1076 }
|
225
|
1077
|
4084
|
1078 if (!(next_frame = (uint8_t *) malloc(in_width * in_height * fb_pixel_size))) {
|
393
|
1079 printf(FBDEV "Can't malloc next_frame: %s\n", strerror(errno));
|
225
|
1080 return 1;
|
4084
|
1081 }
|
|
1082 if (fs || vm)
|
|
1083 memset(frame_buffer, '\0', fb_line_len * fb_yres);
|
|
1084
|
|
1085 if (format == IMGFMT_YV12)
|
|
1086 yuv2rgb_init(fb_bpp, MODE_RGB);
|
225
|
1087 }
|
950
|
1088 if (vt_doit && (vt_fd = open("/dev/tty", O_WRONLY)) == -1) {
|
|
1089 printf(FBDEV "can't open /dev/tty: %s\n", strerror(errno));
|
|
1090 vt_doit = 0;
|
|
1091 }
|
|
1092 if (vt_doit && !(vt_fp = fdopen(vt_fd, "w"))) {
|
|
1093 printf(FBDEV "can't fdopen /dev/tty: %s\n", strerror(errno));
|
|
1094 vt_doit = 0;
|
804
|
1095 }
|
950
|
1096
|
|
1097 if (vt_doit)
|
|
1098 vt_set_textarea(last_row, fb_yres);
|
|
1099
|
225
|
1100 return 0;
|
|
1101 }
|
|
1102
|
|
1103 static uint32_t query_format(uint32_t format)
|
|
1104 {
|
6212
|
1105 int ret = VFCAP_OSD|VFCAP_CSP_SUPPORTED; /* osd/sub is supported on every bpp */
|
519
|
1106
|
950
|
1107 if (!fb_preinit())
|
305
|
1108 return 0;
|
6851
|
1109 #ifdef CONFIG_VIDIX
|
|
1110 if(vidix_name)
|
|
1111 return (vidix_query_fourcc(format));
|
|
1112 #endif
|
311
|
1113 if ((format & IMGFMT_BGR_MASK) == IMGFMT_BGR) {
|
|
1114 int bpp = format & 0xff;
|
519
|
1115
|
359
|
1116 if (bpp == fb_bpp)
|
6212
|
1117 return ret|VFCAP_CSP_SUPPORTED_BY_HW;
|
359
|
1118 else if (bpp == 15 && fb_bpp == 16)
|
6212
|
1119 return ret;
|
359
|
1120 else if (bpp == 24 && fb_bpp == 32)
|
6212
|
1121 return ret;
|
311
|
1122 }
|
|
1123 if (format == IMGFMT_YV12)
|
6212
|
1124 return ret;
|
311
|
1125 return 0;
|
225
|
1126 }
|
|
1127
|
|
1128 static const vo_info_t *get_info(void)
|
|
1129 {
|
|
1130 return &vo_info;
|
|
1131 }
|
|
1132
|
|
1133 static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src,
|
|
1134 unsigned char *srca, int stride)
|
|
1135 {
|
4210
|
1136 unsigned char *dst;
|
|
1137 int dstride;
|
|
1138
|
|
1139 #ifdef USE_CONVERT2FB
|
|
1140 if (pixel_format == IMGFMT_YV12) {
|
|
1141 dst = L123123875 + (fb_xres * y0 + x0) * fb_pixel_size;
|
|
1142 dstride = fb_xres * fb_pixel_size;
|
|
1143 }
|
|
1144 else
|
|
1145 #endif
|
|
1146 {
|
|
1147 dst = next_frame + (in_width * y0 + x0) * fb_pixel_size;
|
|
1148 dstride = in_width * fb_pixel_size;
|
|
1149 }
|
359
|
1150
|
658
|
1151 (*draw_alpha_p)(w, h, src, srca, stride, dst, dstride);
|
225
|
1152 }
|
|
1153
|
|
1154 static uint32_t draw_frame(uint8_t *src[])
|
|
1155 {
|
|
1156 if (pixel_format == IMGFMT_YV12) {
|
4210
|
1157 #ifdef USE_CONVERT2FB
|
|
1158 yuv2rgb(L123123875, src[0], src[1], src[2], fb_xres,
|
|
1159 fb_yres, fb_xres * fb_pixel_size,
|
|
1160 in_width, in_width / 2);
|
|
1161 #else
|
225
|
1162 yuv2rgb(next_frame, src[0], src[1], src[2], in_width,
|
278
|
1163 in_height, in_width * fb_pixel_size,
|
225
|
1164 in_width, in_width / 2);
|
4210
|
1165 #endif
|
|
1166
|
804
|
1167 } else if (flip) {
|
|
1168 int h = in_height;
|
|
1169 int len = in_width * fb_pixel_size;
|
|
1170 char *d = next_frame + (in_height - 1) * len;
|
|
1171 char *s = src[0];
|
|
1172 while (h--) {
|
|
1173 memcpy(d, s, len);
|
|
1174 s += len;
|
|
1175 d -= len;
|
|
1176 }
|
311
|
1177 } else {
|
|
1178 int sbpp = ((pixel_format & 0xff) + 7) / 8;
|
|
1179 char *d = next_frame;
|
|
1180 char *s = src[0];
|
|
1181 if (sbpp == fb_pixel_size) {
|
2556
|
1182 if (fb_real_bpp == 16 && pixel_format == (IMGFMT_BGR|15))
|
|
1183 rgb15to16(s, d, 2 * in_width * in_height);
|
|
1184 else
|
|
1185 memcpy(d, s, sbpp * in_width * in_height);
|
311
|
1186 }
|
|
1187 }
|
225
|
1188 return 0;
|
|
1189 }
|
|
1190
|
|
1191 static uint32_t draw_slice(uint8_t *src[], int stride[], int w, int h, int x,
|
|
1192 int y)
|
|
1193 {
|
|
1194 uint8_t *dest;
|
|
1195
|
4210
|
1196 #ifdef USE_CONVERT2FB
|
|
1197 if (pixel_format == IMGFMT_YV12) {
|
|
1198 if(x < fb_xres && y < fb_yres) {
|
|
1199 if(x+w > fb_xres) w= fb_xres-x;
|
|
1200 if(y+h > fb_yres) h= fb_yres-y;
|
|
1201
|
|
1202 dest = L123123875 + (fb_xres * y + x) * fb_pixel_size;
|
|
1203 yuv2rgb(dest, src[0], src[1], src[2], w, h, fb_xres * fb_pixel_size,
|
|
1204 stride[0], stride[1]);
|
|
1205 }
|
|
1206
|
|
1207 return 0;
|
|
1208 }
|
|
1209 #endif
|
|
1210
|
278
|
1211 dest = next_frame + (in_width * y + x) * fb_pixel_size;
|
|
1212 yuv2rgb(dest, src[0], src[1], src[2], w, h, in_width * fb_pixel_size,
|
225
|
1213 stride[0], stride[1]);
|
|
1214 return 0;
|
|
1215 }
|
|
1216
|
|
1217 static void check_events(void)
|
|
1218 {
|
|
1219 }
|
|
1220
|
519
|
1221 static void put_frame(void)
|
225
|
1222 {
|
|
1223 int i, out_offset = 0, in_offset = 0;
|
|
1224
|
4210
|
1225 #ifdef USE_CONVERT2FB
|
|
1226 if(pixel_format == IMGFMT_YV12)
|
|
1227 return;
|
|
1228 #endif
|
|
1229
|
225
|
1230 for (i = 0; i < in_height; i++) {
|
519
|
1231 memcpy(L123123875 + out_offset, next_frame + in_offset,
|
423
|
1232 in_width * fb_pixel_size);
|
950
|
1233 out_offset += fb_line_len;
|
278
|
1234 in_offset += in_width * fb_pixel_size;
|
225
|
1235 }
|
|
1236 }
|
|
1237
|
1501
|
1238 static void draw_osd(void)
|
|
1239 {
|
|
1240 vo_draw_text(in_width, in_height, draw_alpha);
|
|
1241 }
|
|
1242
|
246
|
1243 static void flip_page(void)
|
|
1244 {
|
519
|
1245 put_frame();
|
246
|
1246 }
|
|
1247
|
225
|
1248 static void uninit(void)
|
|
1249 {
|
379
|
1250 if (verbose > 0)
|
393
|
1251 printf(FBDEV "uninit\n");
|
481
|
1252 if (fb_cmap_changed) {
|
|
1253 if (ioctl(fb_dev_fd, FBIOPUTCMAP, &fb_oldcmap))
|
393
|
1254 printf(FBDEV "Can't restore original cmap\n");
|
481
|
1255 fb_cmap_changed = 0;
|
306
|
1256 }
|
4084
|
1257 if(next_frame) free(next_frame);
|
503
|
1258 if (ioctl(fb_dev_fd, FBIOGET_VSCREENINFO, &fb_vinfo))
|
|
1259 printf(FBDEV "ioctl FBIOGET_VSCREENINFO: %s\n", strerror(errno));
|
|
1260 fb_orig_vinfo.xoffset = fb_vinfo.xoffset;
|
|
1261 fb_orig_vinfo.yoffset = fb_vinfo.yoffset;
|
379
|
1262 if (ioctl(fb_dev_fd, FBIOPUT_VSCREENINFO, &fb_orig_vinfo))
|
503
|
1263 printf(FBDEV "Can't reset original fb_var_screeninfo: %s\n", strerror(errno));
|
2354
|
1264 if (fb_tty_fd >= 0) {
|
|
1265 if (ioctl(fb_tty_fd, KDSETMODE, KD_TEXT) < 0)
|
|
1266 printf(FBDEV "Can't restore text mode: %s\n", strerror(errno));
|
|
1267 }
|
950
|
1268 if (vt_doit)
|
|
1269 vt_set_textarea(0, fb_orig_vinfo.yres);
|
2354
|
1270 close(fb_tty_fd);
|
359
|
1271 close(fb_dev_fd);
|
4084
|
1272 if(frame_buffer) munmap(frame_buffer, fb_size);
|
4089
|
1273 #ifdef CONFIG_VIDIX
|
4084
|
1274 if(vidix_name) vidix_term();
|
4089
|
1275 #endif
|
225
|
1276 }
|
2354
|
1277
|
7676
|
1278 static uint32_t preinit(const char *vo_subdevice)
|
4352
|
1279 {
|
4380
|
1280 pre_init_err = 0;
|
|
1281 #ifdef CONFIG_VIDIX
|
|
1282 if(vo_subdevice) parseSubDevice(vo_subdevice);
|
|
1283 if(vidix_name) pre_init_err = vidix_preinit(vidix_name,&video_out_fbdev);
|
|
1284 if(verbose > 2)
|
|
1285 printf("vo_subdevice: initialization returns: %i\n",pre_init_err);
|
|
1286 #endif
|
|
1287 if(!pre_init_err) return (pre_init_err=(fb_preinit()?0:-1));
|
6164
|
1288 return(-1);
|
4352
|
1289 }
|
|
1290
|
4596
|
1291 static uint32_t control(uint32_t request, void *data, ...)
|
4352
|
1292 {
|
4592
|
1293 switch (request) {
|
|
1294 case VOCTRL_QUERY_FORMAT:
|
|
1295 return query_format(*((uint32_t*)data));
|
|
1296 }
|
|
1297 return VO_NOTIMPL;
|
4352
|
1298 }
|