move around - flatter.
[profile/ivi/evas.git] / src / modules / engines / fb / evas_fb_main.c
1 /* -------------------------------------------------------------------- */
2 /* LINUX FBCON FRAMEBUFFER UTILITY CODE                                 */
3 /* makes setting up the framebuffer easy. Also makes it eays to port to */
4 /* some other system if needed.                                         */
5 /* Copyright (c) 1999 - Carsten Haitzler (The Rasterman)                */
6 /* -------------------------------------------------------------------- */
7 #include "evas_common.h"
8 #include "evas_fb.h"
9
10 #include <signal.h>
11 #include <sys/ioctl.h>
12 #include <sys/wait.h>
13 #include <linux/kd.h>
14 #include <linux/vt.h>
15 #include <sys/user.h>
16
17 #define FB_ACTIVE    0
18 #define FB_REL_REQ   1
19 #define FB_INACTIVE  2
20 #define FB_ACQ_REQ   3
21
22 /* -------------------------------------------------------------------- */
23 /* internal variables                                                   */
24
25 static struct fb_fix_screeninfo  fb_fix;
26 static int                       fb, tty;
27 static int                       bpp, depth;
28 static int                       orig_vt_no = 0;
29 static int                       kd_mode;
30 static struct vt_mode            vt_omode;
31 static struct fb_var_screeninfo  fb_ovar;
32 static unsigned short            ored[256], ogreen[256], oblue[256];
33 static unsigned short            red[256],  green[256],  blue[256];
34 static struct fb_cmap            ocmap = { 0, 256, ored, ogreen, oblue, NULL };
35 static struct fb_cmap            cmap  = { 0, 256, red,  green,  blue, NULL };
36
37 /* -------------------------------------------------------------------- */
38 /* internal function prototypes                                         */
39
40 static void fb_cleanup(void);
41 //static void fb_cleanup_fork(void);
42 static void fb_setvt(int vtno);
43 static void fb_init_palette_332(FB_Mode *mode);
44 static void fb_init_palette_linear(FB_Mode *mode);
45
46 /* -------------------------------------------------------------------- */
47 /* palette setting                                                      */
48
49 static void
50 fb_init_palette_332(FB_Mode *mode)
51 {
52   int r, g, b, i;
53
54   if (mode->fb_var.bits_per_pixel != 8)
55     return;
56   i = 0;
57
58   if (ioctl(fb, FBIOGETCMAP, &cmap) == -1)
59     perror("ioctl FBIOGETCMAP");
60
61   /* generate the palette */
62   for (r = 0; r < 8; r++)
63     {
64       for (g = 0; g < 8; g++)
65         {
66           for (b = 0; b < 4; b++)
67             {
68               int val;
69
70               val = (r << 5) | (r << 2) | (r >> 1);
71               red[i] = (val << 8) | val;
72               val = (g << 5) | (g << 2) | (g >> 1);
73               green[i] = (val << 8) | val;
74               val = (b << 6) | (b << 4) | (b << 2) | (b);
75               blue[i] = (val << 8) | val;
76               i++;
77             }
78         }
79     }
80
81   /* set colormap */
82   if (ioctl(fb, FBIOPUTCMAP, &cmap) == -1)
83     perror("ioctl FBIOPUTCMAP");
84
85 }
86
87 static void
88 fb_init_palette_linear(FB_Mode *mode)
89 {
90   int i;
91
92   if (mode->fb_var.bits_per_pixel != 8)
93     return;
94
95   if (ioctl(fb, FBIOGETCMAP, &cmap) == -1)
96     perror("ioctl FBIOGETCMAP");
97
98   /* generate the palette */
99   for (i = 0; i < 256; i++)
100     red[i] = (i << 8) | i;
101   for (i = 0; i < 256; i++)
102     green[i] = (i << 8) | i;
103   for (i = 0; i < 256; i++)
104     blue[i] = (i << 8) | i;
105
106   /* set colormap */
107   if (ioctl(fb, FBIOPUTCMAP, &cmap) == -1)
108     perror("ioctl FBIOPUTCMAP");
109
110 }
111
112 /* -------------------------------------------------------------------- */
113 /* initialisation & cleanup                                             */
114
115 FB_Mode *
116 fb_list_modes(int *num_return)
117 {
118   FILE *f;
119   char line[256], label[256], value[256];
120   FB_Mode *modes = NULL;
121   int num;
122
123   num = 0;
124   f = fopen("/etc/fb.modes","r");
125   if (!f)
126     {
127       *num_return = 0;
128       return NULL;
129     }
130   while (fgets(line, sizeof(line) - 1, f))
131     {
132       if (sscanf(line, "mode \"%250[^\"]\"", label) == 1)
133         {
134           char f1[32], f2[32], f3[32], f4[32];
135
136           f1[0] = 0; f2[0] = 0; f3[0] = 0; f4[0] = 0;
137           sscanf(label, "%30[^x]x%30[^-]-%30[^-]-%30s", f1, f2, f3, f4);
138           if ((f1[0]) && (f2[0]))
139             {
140               int geometry = 0;
141               int timings = 0;
142
143               num++;
144               modes = realloc(modes, num * sizeof(FB_Mode));
145               modes[num - 1].width = atoi(f1);
146               modes[num - 1].height = atoi(f2);
147               if (f3[0])
148                 modes[num - 1].refresh = atoi(f3);
149               else
150                 modes[num - 1].refresh = 0;
151               modes[num - 1].fb_var.sync = 0;
152               while ((fgets(line, sizeof(line) - 1, f)) &&
153                      (!strstr(line, "endmode")))
154                 {
155
156                   if (sscanf(line," geometry %i %i %i %i %i",
157                              &modes[num - 1].fb_var.xres,
158                              &modes[num - 1].fb_var.yres,
159                              &modes[num - 1].fb_var.xres_virtual,
160                              &modes[num - 1].fb_var.yres_virtual,
161                              &modes[num - 1].fb_var.bits_per_pixel) == 5)
162                     geometry = 1;
163                   if (sscanf(line," timings %i %i %i %i %i %i %i",
164                              &modes[num - 1].fb_var.pixclock,
165                              &modes[num - 1].fb_var.left_margin,
166                              &modes[num - 1].fb_var.right_margin,
167                              &modes[num - 1].fb_var.upper_margin,
168                              &modes[num - 1].fb_var.lower_margin,
169                              &modes[num - 1].fb_var.hsync_len,
170                              &modes[num - 1].fb_var.vsync_len) == 7)
171                     timings = 1;
172                   if ((sscanf(line, " hsync %15s", value) == 1) &&
173                       (!strcmp(value,"high")))
174                     modes[num - 1].fb_var.sync |= FB_SYNC_HOR_HIGH_ACT;
175                   if ((sscanf(line, " vsync %15s", value) == 1) &&
176                       (!strcmp(value,"high")))
177                     modes[num - 1].fb_var.sync |= FB_SYNC_VERT_HIGH_ACT;
178                   if ((sscanf(line, " csync %15s", value) == 1) &&
179                       (!strcmp(value,"high")))
180                     modes[num - 1].fb_var.sync |= FB_SYNC_COMP_HIGH_ACT;
181                   if ((sscanf(line, " extsync %15s", value) == 1) &&
182                       (!strcmp(value,"true")))
183                     modes[num - 1].fb_var.sync |= FB_SYNC_EXT;
184                   if ((sscanf(line, " laced %15s", value) == 1) &&
185                       (!strcmp(value,"true")))
186                     modes[num - 1].fb_var.vmode |= FB_VMODE_INTERLACED;
187                   if ((sscanf(line, " double %15s",value) == 1) &&
188                       (!strcmp(value,"true")))
189                     modes[num - 1].fb_var.vmode |= FB_VMODE_DOUBLE;
190                 }
191               if ((!geometry) || (!timings))
192                 {
193                   num--;
194                   if (num == 0)
195                     {
196                       free(modes);
197                       modes = NULL;
198                     }
199                 }
200               else
201                 {
202                   modes[num - 1].fb_var.xoffset = 0;
203                   modes[num - 1].fb_var.yoffset = 0;
204                 }
205             }
206
207         }
208     }
209   fclose(f);
210   *num_return = num;
211   return modes;
212 }
213
214 FB_Mode *
215 fb_setmode(int width, int height, int depth, int refresh)
216 {
217   FB_Mode *modes, *mode = NULL;
218   int      i, num_modes;
219
220   modes = fb_list_modes(&num_modes);
221   if (modes)
222     {
223       for (i = 0; i < num_modes; i++)
224         {
225           if ((modes[i].width == width) &&
226               (modes[i].height == height) &&
227               (!depth || modes[i].fb_var.bits_per_pixel == depth) &&
228               (modes[i].refresh == refresh))
229             {
230               if (depth) modes[i].fb_var.bits_per_pixel = depth;
231
232               if (ioctl(fb, FBIOPUT_VSCREENINFO, &modes[i].fb_var) == -1)
233                 perror("ioctl FBIOPUT_VSCREENINFO");
234
235               free(modes);
236               return fb_getmode();
237             }
238         }
239       free(modes);
240     }
241   return mode;
242 }
243
244 FB_Mode *
245 fb_changedepth(FB_Mode *cur_mode, int depth)
246 {
247   cur_mode->fb_var.bits_per_pixel = depth;
248
249   if (ioctl(fb, FBIOPUT_VSCREENINFO, &cur_mode->fb_var) == -1)
250     perror("ioctl FBIOPUT_VSCREENINFO");
251
252   free(cur_mode);
253   return fb_getmode();
254 }
255
256 FB_Mode *
257 fb_changeres(FB_Mode *cur_mode, int width, int height, int refresh)
258 {
259   FB_Mode *modes;
260   int      i, num_modes;
261
262   modes = fb_list_modes(&num_modes);
263   if (modes)
264     {
265       for (i = 0; i < num_modes; i++)
266         {
267           if ((modes[i].width == width) &&
268               (modes[i].height == height) &&
269               (modes[i].refresh == refresh))
270             {
271               modes[i].fb_var.bits_per_pixel = cur_mode->depth;
272
273               if (ioctl(fb, FBIOPUT_VSCREENINFO, &modes[i].fb_var) == -1)
274                 perror("ioctl FBIOPUT_VSCREENINFO");
275
276               free(modes);
277               free(cur_mode);
278               return fb_getmode();
279             }
280         }
281       free(modes);
282     }
283   return cur_mode;
284 }
285
286 FB_Mode *
287 fb_changemode(FB_Mode *cur_mode, int width, int height, int depth, int refresh)
288 {
289   FB_Mode *modes;
290   int      i, num_modes;
291
292   modes = fb_list_modes(&num_modes);
293   if (modes)
294     {
295       for (i = 0; i < num_modes; i++)
296         {
297           if ((modes[i].width == width) &&
298               (modes[i].height == height) &&
299               (!depth || modes[i].fb_var.bits_per_pixel == depth) &&
300               (modes[i].refresh == refresh))
301             {
302               if (depth) modes[i].fb_var.bits_per_pixel = depth;
303
304               if (ioctl(fb, FBIOPUT_VSCREENINFO, &modes[i].fb_var) == -1)
305                 perror("ioctl FBIOPUT_VSCREENINFO");
306
307               free(modes);
308               free(cur_mode);
309               return fb_getmode();
310             }
311         }
312       free(modes);
313     }
314   return cur_mode;
315 }
316
317 FB_Mode *
318 fb_getmode(void)
319 {
320   FB_Mode *mode = NULL;
321   int      hpix, lines, clockrate;
322
323   mode = malloc(sizeof(FB_Mode));
324   /* look what we have now ... */
325
326   if (ioctl(fb, FBIOGET_VSCREENINFO, &mode->fb_var) == -1)
327     {
328       perror("ioctl FBIOGET_VSCREENINFO");
329       exit(1);
330     }
331
332   mode->width = mode->fb_var.xres;
333   mode->height = mode->fb_var.yres;
334   hpix =
335     mode->fb_var.left_margin +
336     mode->fb_var.xres +
337     mode->fb_var.right_margin +
338     mode->fb_var.hsync_len;
339   lines =
340     mode->fb_var.upper_margin +
341     mode->fb_var.yres +
342     mode->fb_var.lower_margin +
343     mode->fb_var.vsync_len;
344    if (mode->fb_var.pixclock > 0)
345      clockrate = 1000000 / mode->fb_var.pixclock;
346    else
347      clockrate = 0;
348    if ((lines > 0) && (hpix > 0))
349      mode->refresh = clockrate * 1000000 / (lines * hpix);
350   switch (mode->fb_var.bits_per_pixel)
351     {
352      case 1:
353       bpp = 1;
354       depth = 1;
355       break;
356      case 4:
357       bpp = 1;
358       depth = 4;
359       break;
360      case 8:
361       bpp = 1;
362       depth = 8;
363       break;
364      case 15:
365      case 16:
366       if (mode->fb_var.green.length == 6)
367         depth = 16;
368       else
369         depth = 15;
370       bpp = 2;
371       break;
372      case 24:
373       depth = 24;
374       bpp = mode->fb_var.bits_per_pixel / 8;
375       break;
376      case 32:
377       depth = 32;
378       bpp = mode->fb_var.bits_per_pixel / 8;
379       break;
380      default:
381       fprintf(stderr, "Cannot handle framebuffer of depth %i\n",
382               mode->fb_var.bits_per_pixel);
383       fb_cleanup();
384        free(mode);
385       return NULL;
386   }
387   mode->depth = depth;
388   mode->bpp = bpp;
389   if (mode->depth == 8)
390     fb_init_palette_332(mode);
391   else
392     fb_init_palette_linear(mode);
393   return mode;
394 }
395
396 static void
397 fb_setvt(int vtno)
398 {
399   struct vt_stat vts;
400   char vtname[32];
401
402   if (vtno < 0)
403     {
404
405       if ((ioctl(tty,VT_OPENQRY, &vtno) == -1))
406         {
407           perror("ioctl VT_OPENQRY");
408           exit(1);
409         }
410       if (vtno <= 0 )
411         {
412           perror("ioctl VT_OPENQRY vtno <= 0");
413           exit(1);
414         }
415
416     }
417   vtno &= 0xff;
418   sprintf(vtname, "/dev/tty%i", vtno);
419   chown(vtname, getuid(), getgid());
420   if (access(vtname,R_OK | W_OK) == -1)
421     {
422       fprintf(stderr,"access %s: %s\n",vtname,strerror(errno));
423       exit(1);
424     }
425   open(vtname,O_RDWR);
426
427   if (ioctl(tty, VT_GETSTATE, &vts) == -1)
428     {
429       perror("ioctl VT_GETSTATE");
430       exit(1);
431     }
432
433   orig_vt_no = vts.v_active;
434 /*
435   if (ioctl(tty, VT_ACTIVATE, vtno) == -1)
436     {
437       perror("ioctl VT_ACTIVATE");
438       exit(1);
439     }
440   if (ioctl(tty, VT_WAITACTIVE, vtno) == -1)
441     {
442       perror("ioctl VT_WAITACTIVE");
443       exit(1);
444     }
445 */
446
447 }
448
449 void
450 fb_init(int vt, int device)
451 {
452    char dev[32];
453
454    tty = 0;
455 #if 0
456    if (vt != 0) fb_setvt(vt);
457 #endif
458    sprintf(dev, "/dev/fb/%i", device);
459    fb = open(dev, O_RDWR);
460    if ( fb == -1 )
461      {
462        sprintf(dev, "/dev/fb%i", device);
463        fb = open(dev, O_RDWR);
464      }
465    if (fb == -1)
466      {
467         fprintf(stderr,"open %s: %s\n", dev, strerror(errno));
468         fb_cleanup();
469         exit(1);
470      }
471
472    if (ioctl(fb, FBIOGET_VSCREENINFO, &fb_ovar) == -1)
473      {
474         perror("ioctl FBIOGET_VSCREENINFO");
475         exit(1);
476      }
477    if (ioctl(fb, FBIOGET_FSCREENINFO, &fb_fix) == -1)
478      {
479         perror("ioctl FBIOGET_FSCREENINFO");
480         exit(1);
481      }
482
483    if ((fb_ovar.bits_per_pixel == 8) ||
484        (fb_fix.visual == FB_VISUAL_DIRECTCOLOR))
485      {
486
487         if (ioctl(fb,FBIOGETCMAP , &ocmap) == -1)
488           {
489              perror("ioctl FBIOGETCMAP");
490              exit(1);
491           }
492
493      }
494 #if 0
495    if (isatty(0))
496       tty = 0;
497    else if ((tty = open("/dev/tty",O_RDWR)) == -1)
498      {
499         fprintf(stderr,"open %s: %s\n", "/dev/tty", strerror(errno));
500         exit(1);
501      }
502    if (tty)
503      {
504         if (ioctl(tty, KDGETMODE, &kd_mode) == -1)
505           {
506              perror("ioctl KDGETMODE");
507              exit(1);
508           }
509         if (ioctl(tty, VT_GETMODE, &vt_omode) == -1)
510           {
511              perror("ioctl VT_GETMODE");
512              exit(1);
513           }
514      }
515 #endif
516 }
517
518 int
519 fb_postinit(FB_Mode *mode)
520 {
521
522   if (ioctl(fb,FBIOGET_FSCREENINFO, &fb_fix) == -1)
523     {
524       perror("ioctl FBIOGET_FSCREENINFO");
525       fb_cleanup();
526       exit(1);
527     }
528
529   if (fb_fix.type != FB_TYPE_PACKED_PIXELS)
530     {
531       fprintf(stderr,"can handle only packed pixel frame buffers\n");
532       fb_cleanup();
533       exit(1);
534     }
535   mode->mem_offset = (unsigned)(fb_fix.smem_start) & (getpagesize()-1);
536   mode->mem = (unsigned char *)mmap(NULL, fb_fix.smem_len + mode->mem_offset,
537                                  PROT_WRITE | PROT_READ, MAP_SHARED, fb, 0);
538   if (mode->mem == MAP_FAILED)
539     {
540       perror("mmap");
541       fb_cleanup();
542   }
543   /* move viewport to upper left corner */
544   if ((mode->fb_var.xoffset != 0) || (mode->fb_var.yoffset != 0))
545     {
546       mode->fb_var.xoffset = 0;
547       mode->fb_var.yoffset = 0;
548
549       if (ioctl(fb, FBIOPAN_DISPLAY, &(mode->fb_var)) == -1)
550         {
551           perror("ioctl FBIOPAN_DISPLAY");
552           fb_cleanup();
553         }
554     }
555 #if 0
556    if (tty)
557      {
558         if (ioctl(tty,KDSETMODE, KD_GRAPHICS) == -1)
559           {
560              perror("ioctl KDSETMODE");
561              fb_cleanup();
562           }
563      }
564 #endif
565   mode->fb_fd = fb;
566   return fb;
567 }
568
569 static void
570 fb_cleanup(void)
571 {
572   /* restore console */
573
574   if (ioctl(fb, FBIOPUT_VSCREENINFO, &fb_ovar) == -1)
575     perror("ioctl FBIOPUT_VSCREENINFO");
576   if (ioctl(fb, FBIOGET_FSCREENINFO, &fb_fix) == -1)
577     perror("ioctl FBIOGET_FSCREENINFO");
578
579   if ((fb_ovar.bits_per_pixel == 8) ||
580       (fb_fix.visual == FB_VISUAL_DIRECTCOLOR))
581     {
582
583       if (ioctl(fb, FBIOPUTCMAP, &ocmap) == -1)
584         perror("ioctl FBIOPUTCMAP");
585
586     }
587   close(fb);
588
589
590    if (tty)
591      {
592         if (ioctl(tty, KDSETMODE, kd_mode) == -1)
593           perror("ioctl KDSETMODE");
594         if (ioctl(tty, VT_SETMODE, &vt_omode) == -1)
595           perror("ioctl VT_SETMODE");
596 /*      if ((ioctl(tty, VT_ACTIVATE, orig_vt_no) == -1) && (orig_vt_no))
597           perror("ioctl VT_ACTIVATE");
598 */     }
599
600   close(tty);
601 }