Add op_test_inputs
[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/omap2_mcspi.1/spi1.1/gamma", "r+");
249         if (f != NULL) {
250                 int *g = gamma;
251                 rewind(f);
252                 ret = fscanf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
253                         &g[0], &g[1], &g[2], &g[3], &g[4],  &g[5],
254                         &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
255         }
256
257         if (ret != 12) {
258                 fprintf(stderr, "gamma file missing or bad\n");
259                 goto out;
260         }
261
262         while (1)
263         {
264                 if (f != NULL) {
265                         int *g = gamma;
266                         rewind(f);
267                         fscanf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
268                                 &g[0], &g[1], &g[2], &g[3], &g[4],  &g[5],
269                                 &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
270                 }
271
272                 //ioctl(fbdev, FBIO_WAITFORVSYNC, &ret);
273                 if (fbvar.bits_per_pixel == 16)
274                 {
275                         dotsz = 2;
276                         DO_RGB(unsigned short, dest[i],, 5, 6, 5);
277                 }
278                 else if (fbvar.bits_per_pixel == 24)
279                 {
280                         // BGR?
281                         unsigned char *p;
282                         unsigned int d = 0;
283                         dotsz = 3;
284                         DO_RGB(unsigned char, d, p = &dest[i*3]; p[0] = d; p[1] = d >> 8; p[2] = d >> 16, 8, 8, 8);
285                 }
286                 else if (fbvar.bits_per_pixel == 32)
287                 {
288                         dotsz = 4;
289                         DO_RGB(unsigned int, dest[i],, 8, 8, 8);
290                 }
291                 else
292                 {
293                         fprintf(stderr, "unhandled bpp: %d\n", fbvar.bits_per_pixel);
294                         goto out;
295                 }
296                 stride = dotsz * w;
297
298                 snprintf(buff, sizeof(buff), "%dbpp", fbvar.bits_per_pixel);
299                 text_out(ptr, 8, 10, dotsz, stride, buff);
300                 if (msg_once != NULL) {
301                         text_out(ptr, 80, 10, dotsz, stride, msg_once);
302                         msg_once = NULL;
303                 }
304                 for (i = 0; i < 12; i++) {
305                         int x = i * w / 12 + 8;
306                         if (i == sel)
307                                 text_out(ptr, x, h - 18, dotsz, stride, "____");
308                         snprintf(buff, sizeof(buff), "%d", gamma[i]);
309                         text_out(ptr, x, h - 20, dotsz, stride, buff);
310                 }
311
312                 // do input
313                 if (ifd == -1)
314                         break;
315
316                 while (1)
317                 {
318                         struct input_event ev;
319                         ret = read(ifd, &ev, sizeof(ev));
320                         if (ret < (int) sizeof(ev)) {
321                                 if (errno == EAGAIN || errno == EWOULDBLOCK)
322                                         goto input_no_change;
323
324                                 perror("evtest: read error");
325                                 goto out;
326                         }
327
328                         if (ev.type != EV_KEY)
329                                 continue;
330
331                         switch (ev.code) {
332                         case KEY_LEFT:
333                                 if (ev.value)
334                                         sel--;
335                                 if (sel < 0)
336                                         sel = 11;
337                                 goto input_done;
338                         case KEY_RIGHT:
339                                 if (ev.value)
340                                         sel++;
341                                 if (sel > 11)
342                                         sel = 0;
343                                 goto input_done;
344                         case KEY_UP:
345                                 pressed_up = ev.value;
346                                 break;
347                         case KEY_DOWN:
348                                 pressed_down = ev.value;
349                                 break;
350                         case KEY_RIGHTCTRL:
351                         case BTN_TR:
352                                 pressed_r = ev.value;
353                                 break;
354                         case KEY_PAGEUP:
355                         case BTN_BASE:
356                                 if (ev.value) {
357                                         fbvar.bits_per_pixel += 8;
358                                         if (fbvar.bits_per_pixel > 32)
359                                                 fbvar.bits_per_pixel = 16;
360                                         ret = ioctl(fbdev, FBIOPUT_VSCREENINFO, &fbvar);
361                                         if (ret == -1)
362                                                 perror("ioctl FBIOPUT_VSCREENINFO");
363                                 }
364                                 goto input_done;
365                         case KEY_END:
366                         case BTN_BASE2:
367                                 if (!ev.value)
368                                         break;
369                                 if (do_load(gamma) == 0)
370                                         msg_once = "loaded";
371                                 else
372                                         msg_once = "load failed";
373                                 goto input_done_gamma;
374                         case KEY_HOME:
375                         case BTN_BASE4:
376                                 if (!ev.value)
377                                         break;
378                                 if (do_save(gamma) == 0)
379                                         msg_once = "saved";
380                                 else
381                                         msg_once = "save failed";
382                                 goto input_done;
383                         case KEY_LEFTALT:
384                         case BTN_START:
385                                 goto out;
386                         case KEY_LEFTCTRL:
387                         case BTN_SELECT:
388                                 goto out;
389                         }
390
391 input_no_change:
392                         if (pressed_up) {
393                                 gamma[sel]++;
394                                 if (gamma[sel] >= 1023)
395                                         gamma[sel] = 1023;
396                                 if (!pressed_r)
397                                         usleep(30000);
398                                 goto input_done_gamma;
399                         }
400                         if (pressed_down) {
401                                 gamma[sel]--;
402                                 if (gamma[sel] < 0)
403                                         gamma[sel] = 0;
404                                 if (!pressed_r)
405                                         usleep(30000);
406                                 goto input_done_gamma;
407                         }
408
409                         usleep(10000);
410                 }
411
412 input_done_gamma:
413                 if (f != NULL) {
414                         int *g = gamma;
415                         rewind(f);
416                         fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
417                                 g[0], g[1], g[2], g[3], g[4],  g[5],
418                                 g[6], g[7], g[8], g[9], g[10], g[11]);
419                 }
420 input_done:;
421         }
422
423 out:
424         munmap(ptr, fbvar.xres * fbvar.yres * fbvar.bits_per_pixel / 8);
425         close(fbdev);
426         if (ifd != -1)
427                 close(ifd);
428         return 0;
429 }
430