op_runfbapp: don't do console when under X
[pandora-misc.git] / op_gammatool.c
1 /*
2  * Copyright (c) 2010, GraÅžvydas Ignotas
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the organization nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 #define _GNU_SOURCE
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <errno.h>
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <sys/mman.h>
37 #include <unistd.h>
38 #include <sys/ioctl.h>
39 #include <linux/fb.h>
40 #include <linux/input.h>
41 #include <linux/matroxfb.h>
42
43
44 #define SPLIT 12
45
46 #define DO_RGB(type,d,after,r,g,b) { \
47         int i, u, c, l, div = (w << 8) / SPLIT; \
48         char lines[8][dotsz * w]; \
49         type *dest; \
50         for (dest = (void *)lines[0], i = 0; i < w; i++) { \
51                 d = (i * (1 << r) / w) << (g+b); \
52                 after; \
53         } \
54         for (dest = (void *)lines[1], i = 0; i < w; i++) { \
55                 d = (i * (1 << g) / w) << b; \
56                 after; \
57         } \
58         for (dest = (void *)lines[2], i = 0; i < w; i++) { \
59                 d = (i * (1 << b) / w); \
60                 after; \
61         } \
62         for (dest = (void *)lines[3], i = 0; i < w; i++) { \
63                 d = ((i * (1 << r) / w) << (g+b)) | \
64                     ((i * (1 << g) / w) << b) | \
65                     (i * (1 << b) / w); \
66                 after; \
67         } \
68 \
69         for (dest = (void *)lines[4], i = 0; i < w; i++) { \
70                 c = (((i << 8) / div + 1) * div) >> 8; \
71                 d = ((c * (1 << r) / w) << (g+b)) | \
72                     ((c * (1 << g) / w) << b) | \
73                     (c * (1 << b) / w); \
74                 after; \
75         } \
76         for (dest = (void *)lines[5], i = 0; i < w; i++) { \
77                 c = (((i << 8) / div + 1) * div) >> 8; \
78                 d = (c * (1 << b) / w); \
79                 after; \
80         } \
81         for (dest = (void *)lines[6], i = 0; i < w; i++) { \
82                 c = (((i << 8) / div + 1) * div) >> 8; \
83                 d = (c * (1 << g) / w) << b; \
84                 after; \
85         } \
86         for (dest = (void *)lines[7], i = 0; i < w; i++) { \
87                 c = (((i << 8) / div + 1) * div) >> 8; \
88                 d = (c * (1 << r) / w) << (g+b); \
89                 after; \
90         } \
91 \
92         for (u = 0; u < h; u++) { \
93                 l = u / (h / 8); \
94                 memcpy((char *)ptr + u * dotsz * w, lines[l], dotsz * w); \
95         } \
96 }
97
98 #include "font.c"
99
100 static void text_out(void *fbi, int x, int y, int dotsz, int stride, const char *text)
101 {
102         int i, l, v = -1;
103         char *fb;
104
105         fb = (char *)fbi + x * dotsz + y * stride;
106
107         for (i = 0; i < strlen(text); i++)
108         {
109                 for (l=0;l<8;l++)
110                 {
111                         #define pix(fdmask,add) \
112                                 if (fontdata8x8[((text[i])*8)+l]&fdmask) \
113                                         memcpy(fb + l*stride + add*dotsz, &v, dotsz)
114                         pix(0x80,  0);
115                         pix(0x40,  1);
116                         pix(0x20,  2);
117                         pix(0x10,  3);
118                         pix(0x08,  4);
119                         pix(0x04,  5);
120                         pix(0x02,  6);
121                         pix(0x01,  7);
122                         #undef pix
123                 }
124                 fb += dotsz * 8;
125         }
126 }
127
128 static void get_config(char *buff, size_t size, int just_dir)
129 {
130         char *home;
131
132         home = getenv("HOME");
133         if (home == NULL)
134                 home = "";
135         if (just_dir)
136                 snprintf(buff, size, "%s/.config", home);
137         else
138                 snprintf(buff, size, "%s/.config/op_gammatool", home);
139 }
140
141 static int do_load(int *gamma)
142 {
143         int ret, *g = gamma;
144         char buff[128];
145         FILE *f;
146
147         get_config(buff, sizeof(buff), 0);
148         f = fopen(buff, "r");
149         if (f == NULL)
150                 return -1;
151         ret = fscanf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
152                 &g[0], &g[1], &g[2], &g[3], &g[4],  &g[5],
153                 &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
154         fclose(f);
155
156         return (ret == 12) ? 0 : -1;
157 }
158
159 static int do_save(const int *gamma)
160 {
161         const int *g = gamma;
162         char buff[128];
163         FILE *f;
164         int ret;
165
166         get_config(buff, sizeof(buff), 1);
167         mkdir(buff, 0644);
168         get_config(buff, sizeof(buff), 0);
169         f = fopen(buff, "w");
170         if (f == NULL)
171                 return -1;
172         ret = fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
173                 g[0], g[1], g[2], g[3], g[4],  g[5],
174                 g[6], g[7], g[8], g[9], g[10], g[11]);
175         fclose(f);
176
177         return (ret > 0) ? 0 : -1;
178 }
179
180 int main(int argc, char *argv[])
181 {
182         const char *msg_once = "Start - exit, Y - change bpp, A/B - save/load, "
183                                 "hold R for faster tuning";
184         int pressed_up = 0, pressed_down = 0, pressed_r = 0;
185         struct fb_var_screeninfo fbvar;
186         int fbdev, ifd, ret, sel = 0;
187         int i, w, h, dotsz = 0, stride;
188         int gamma[12] = { 0, };
189         char buff[64];
190         FILE *f;
191         void *ptr;
192
193         fbdev = open("/dev/fb0", O_RDWR);
194         if (fbdev == -1) {
195                 perror("open(\"/dev/fb0\") failed");
196                 return 1;
197         }
198
199         ret = ioctl(fbdev, FBIOGET_VSCREENINFO, &fbvar);
200         if (ret == -1) {
201                 perror("ioctl(FBIOGET_FSCREENINFO) failed");
202                 return 1;
203         }
204
205         if (argv[1] != NULL) {
206                 fbvar.bits_per_pixel = atoi(argv[1]);
207                 ret = ioctl(fbdev, FBIOPUT_VSCREENINFO, &fbvar);
208                 if (ret == -1)
209                 {
210                         perror("ioctl FBIOPUT_VSCREENINFO");
211                 }
212         }
213
214         printf("visible resolution: %i %i\n", fbvar.xres, fbvar.yres);
215         printf("virtual resolution: %i %i\n", fbvar.xres_virtual, fbvar.yres_virtual);
216         printf("offset from virtual to visible: %i %i\n", fbvar.xoffset, fbvar.yoffset);
217         printf("bits_per_pixel: %i\n", fbvar.bits_per_pixel);
218
219         ptr = mmap(0, fbvar.xres * fbvar.yres * 4,
220                         PROT_WRITE|PROT_READ, MAP_SHARED, fbdev, 0);
221         if (ptr == MAP_FAILED)
222                 ptr = mmap(0, fbvar.xres * fbvar.yres * fbvar.bits_per_pixel / 8,
223                                 PROT_WRITE|PROT_READ, MAP_SHARED, fbdev, 0);
224         if (ptr == MAP_FAILED)
225         {
226                 perror("mmap(fbptr) failed");
227                 return 1;
228         }
229
230         w = fbvar.xres;
231         h = fbvar.yres;
232
233         // search for gpio keys
234         for (ifd = -1, i = 0; ; i++) {
235                 snprintf(buff, sizeof(buff), "/dev/input/event%i", i);
236                 ifd = open(buff, O_RDONLY | O_NONBLOCK);
237                 if (ifd == -1)
238                         break;
239
240                 ioctl(ifd, EVIOCGNAME(sizeof(buff)), buff);
241
242                 if (strcasestr(buff, "gpio") != NULL)
243                         break;
244                 close(ifd);
245         }
246
247         ret = 0;
248         f = fopen("/sys/devices/platform/omapdss/display0/gamma", "r+");
249         if (f == NULL)
250                 f = fopen("/sys/devices/platform/omap2_mcspi.1/spi1.1/gamma", "r+");
251         if (f != NULL) {
252                 int *g = gamma;
253                 rewind(f);
254                 ret = fscanf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
255                         &g[0], &g[1], &g[2], &g[3], &g[4],  &g[5],
256                         &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
257         }
258
259         if (ret != 12) {
260                 fprintf(stderr, "gamma file missing or bad\n");
261                 goto out;
262         }
263
264         while (1)
265         {
266                 if (f != NULL) {
267                         int *g = gamma;
268                         rewind(f);
269                         fscanf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
270                                 &g[0], &g[1], &g[2], &g[3], &g[4],  &g[5],
271                                 &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
272                 }
273
274                 //ioctl(fbdev, FBIO_WAITFORVSYNC, &ret);
275                 if (fbvar.bits_per_pixel == 16)
276                 {
277                         dotsz = 2;
278                         DO_RGB(unsigned short, dest[i],, 5, 6, 5);
279                 }
280                 else if (fbvar.bits_per_pixel == 24)
281                 {
282                         // BGR?
283                         unsigned char *p;
284                         unsigned int d = 0;
285                         dotsz = 3;
286                         DO_RGB(unsigned char, d, p = &dest[i*3]; p[0] = d; p[1] = d >> 8; p[2] = d >> 16, 8, 8, 8);
287                 }
288                 else if (fbvar.bits_per_pixel == 32)
289                 {
290                         dotsz = 4;
291                         DO_RGB(unsigned int, dest[i],, 8, 8, 8);
292                 }
293                 else
294                 {
295                         fprintf(stderr, "unhandled bpp: %d\n", fbvar.bits_per_pixel);
296                         goto out;
297                 }
298                 stride = dotsz * w;
299
300                 snprintf(buff, sizeof(buff), "%dbpp", fbvar.bits_per_pixel);
301                 text_out(ptr, 8, 10, dotsz, stride, buff);
302                 if (msg_once != NULL) {
303                         text_out(ptr, 80, 10, dotsz, stride, msg_once);
304                         msg_once = NULL;
305                 }
306                 for (i = 0; i < 12; i++) {
307                         int x = i * w / 12 + 8;
308                         if (i == sel)
309                                 text_out(ptr, x, h - 18, dotsz, stride, "____");
310                         snprintf(buff, sizeof(buff), "%d", gamma[i]);
311                         text_out(ptr, x, h - 20, dotsz, stride, buff);
312                 }
313
314                 // do input
315                 if (ifd == -1)
316                         break;
317
318                 while (1)
319                 {
320                         struct input_event ev;
321                         ret = read(ifd, &ev, sizeof(ev));
322                         if (ret < (int) sizeof(ev)) {
323                                 if (errno == EAGAIN || errno == EWOULDBLOCK)
324                                         goto input_no_change;
325
326                                 perror("evtest: read error");
327                                 goto out;
328                         }
329
330                         if (ev.type != EV_KEY)
331                                 continue;
332
333                         switch (ev.code) {
334                         case KEY_LEFT:
335                                 if (ev.value)
336                                         sel--;
337                                 if (sel < 0)
338                                         sel = 11;
339                                 goto input_done;
340                         case KEY_RIGHT:
341                                 if (ev.value)
342                                         sel++;
343                                 if (sel > 11)
344                                         sel = 0;
345                                 goto input_done;
346                         case KEY_UP:
347                                 pressed_up = ev.value;
348                                 break;
349                         case KEY_DOWN:
350                                 pressed_down = ev.value;
351                                 break;
352                         case KEY_RIGHTCTRL:
353                         case BTN_TR:
354                                 pressed_r = ev.value;
355                                 break;
356                         case KEY_PAGEUP:
357                         case BTN_BASE:
358                                 if (ev.value) {
359                                         fbvar.bits_per_pixel += 8;
360                                         if (fbvar.bits_per_pixel > 32)
361                                                 fbvar.bits_per_pixel = 16;
362                                         ret = ioctl(fbdev, FBIOPUT_VSCREENINFO, &fbvar);
363                                         if (ret == -1)
364                                                 perror("ioctl FBIOPUT_VSCREENINFO");
365                                 }
366                                 goto input_done;
367                         case KEY_END:
368                         case BTN_BASE2:
369                                 if (!ev.value)
370                                         break;
371                                 if (do_load(gamma) == 0)
372                                         msg_once = "loaded";
373                                 else
374                                         msg_once = "load failed";
375                                 goto input_done_gamma;
376                         case KEY_HOME:
377                         case BTN_BASE4:
378                                 if (!ev.value)
379                                         break;
380                                 if (do_save(gamma) == 0)
381                                         msg_once = "saved";
382                                 else
383                                         msg_once = "save failed";
384                                 goto input_done;
385                         case KEY_LEFTALT:
386                         case BTN_START:
387                                 goto out;
388                         case KEY_LEFTCTRL:
389                         case BTN_SELECT:
390                                 goto out;
391                         }
392
393 input_no_change:
394                         if (pressed_up) {
395                                 gamma[sel]++;
396                                 if (gamma[sel] >= 1023)
397                                         gamma[sel] = 1023;
398                                 if (!pressed_r)
399                                         usleep(30000);
400                                 goto input_done_gamma;
401                         }
402                         if (pressed_down) {
403                                 gamma[sel]--;
404                                 if (gamma[sel] < 0)
405                                         gamma[sel] = 0;
406                                 if (!pressed_r)
407                                         usleep(30000);
408                                 goto input_done_gamma;
409                         }
410
411                         usleep(10000);
412                 }
413
414 input_done_gamma:
415                 if (f != NULL) {
416                         int *g = gamma;
417                         rewind(f);
418                         fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
419                                 g[0], g[1], g[2], g[3], g[4],  g[5],
420                                 g[6], g[7], g[8], g[9], g[10], g[11]);
421                 }
422 input_done:;
423         }
424
425 out:
426         munmap(ptr, fbvar.xres * fbvar.yres * fbvar.bits_per_pixel / 8);
427         close(fbdev);
428         if (ifd != -1)
429                 close(ifd);
430         return 0;
431 }
432