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