op_runfbapp and op_gammatool
authorGrazvydas Ignotas <notasas@gmail.com>
Mon, 29 Mar 2010 09:39:01 +0000 (12:39 +0300)
committerGrazvydas Ignotas <notasas@gmail.com>
Mon, 29 Mar 2010 09:39:01 +0000 (12:39 +0300)
Makefile [new file with mode: 0644]
font.c [new file with mode: 0644]
op_gammatool.c [new file with mode: 0644]
op_runfbapp.c [new file with mode: 0644]
scripts/op_gammatool [new file with mode: 0755]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..b77ba5a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,23 @@
+CROSS_COMPILE ?= arm-none-linux-gnueabi-
+CC = $(CROSS_COMPILE)gcc
+
+CFLAGS += -Wall -O2
+LDFLAGS += -s
+INSTALL ?= bin
+
+BIN = op_runfbapp op_gammatool
+
+all: $(BIN)
+
+clean:
+       $(RM) *.o $(BIN)
+
+op_runfbapp: LDFLAGS += -lpthread -lX11
+
+$(INSTALL):
+       mkdir -p $(INSTALL)
+
+install: $(INSTALL) $(BIN)
+       cp op_runfbapp $(INSTALL)/
+       cp op_gammatool $(INSTALL)/op_gammatool_bin
+       cp scripts/op_gammatool $(INSTALL)/op_gammatool
diff --git a/font.c b/font.c
new file mode 100644 (file)
index 0000000..3a9553f
--- /dev/null
+++ b/font.c
@@ -0,0 +1,70 @@
+/* CGA 8x8 font? */
+
+static const unsigned char fontdata8x8[64*16] =
+{
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+       0x3C,0x42,0x99,0xBD,0xBD,0x99,0x42,0x3C,0x3C,0x42,0x81,0x81,0x81,0x81,0x42,0x3C,
+       0xFE,0x82,0x8A,0xD2,0xA2,0x82,0xFE,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0xFE,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00,
+       0x80,0xC0,0xF0,0xFC,0xF0,0xC0,0x80,0x00,0x01,0x03,0x0F,0x3F,0x0F,0x03,0x01,0x00,
+       0x18,0x3C,0x7E,0x18,0x7E,0x3C,0x18,0x00,0xEE,0xEE,0xEE,0xCC,0x00,0xCC,0xCC,0x00,
+       0x00,0x00,0x30,0x68,0x78,0x30,0x00,0x00,0x00,0x38,0x64,0x74,0x7C,0x38,0x00,0x00,
+       0x3C,0x66,0x7A,0x7A,0x7E,0x7E,0x3C,0x00,0x0E,0x3E,0x3A,0x22,0x26,0x6E,0xE4,0x40,
+       0x18,0x3C,0x7E,0x3C,0x3C,0x3C,0x3C,0x00,0x3C,0x3C,0x3C,0x3C,0x7E,0x3C,0x18,0x00,
+       0x08,0x7C,0x7E,0x7E,0x7C,0x08,0x00,0x00,0x10,0x3E,0x7E,0x7E,0x3E,0x10,0x00,0x00,
+       0x58,0x2A,0xDC,0xC8,0xDC,0x2A,0x58,0x00,0x24,0x66,0xFF,0xFF,0x66,0x24,0x00,0x00,
+       0x00,0x10,0x10,0x38,0x38,0x7C,0xFE,0x00,0xFE,0x7C,0x38,0x38,0x10,0x10,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x18,0x00,0x18,0x18,0x00,
+       0x6C,0x6C,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7C,0x28,0x7C,0x28,0x00,0x00,
+       0x10,0x38,0x60,0x38,0x0C,0x78,0x10,0x00,0x40,0xA4,0x48,0x10,0x24,0x4A,0x04,0x00,
+       0x18,0x34,0x18,0x3A,0x6C,0x66,0x3A,0x00,0x18,0x18,0x20,0x00,0x00,0x00,0x00,0x00,
+       0x30,0x60,0x60,0x60,0x60,0x60,0x30,0x00,0x0C,0x06,0x06,0x06,0x06,0x06,0x0C,0x00,
+       0x10,0x54,0x38,0x7C,0x38,0x54,0x10,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00,
+       0x38,0x4C,0xC6,0xC6,0xC6,0x64,0x38,0x00,0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00,
+       0x7C,0xC6,0x0E,0x3C,0x78,0xE0,0xFE,0x00,0x7E,0x0C,0x18,0x3C,0x06,0xC6,0x7C,0x00,
+       0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x00,0xFC,0xC0,0xFC,0x06,0x06,0xC6,0x7C,0x00,
+       0x3C,0x60,0xC0,0xFC,0xC6,0xC6,0x7C,0x00,0xFE,0xC6,0x0C,0x18,0x30,0x30,0x30,0x00,
+       0x78,0xC4,0xE4,0x78,0x86,0x86,0x7C,0x00,0x7C,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00,
+       0x00,0x00,0x18,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x18,0x18,0x30,
+       0x1C,0x38,0x70,0xE0,0x70,0x38,0x1C,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00,
+       0x70,0x38,0x1C,0x0E,0x1C,0x38,0x70,0x00,0x7C,0xC6,0xC6,0x1C,0x18,0x00,0x18,0x00,
+       0x3C,0x42,0x99,0xA1,0xA5,0x99,0x42,0x3C,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00,
+       0xFC,0xC6,0xC6,0xFC,0xC6,0xC6,0xFC,0x00,0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00,
+       0xF8,0xCC,0xC6,0xC6,0xC6,0xCC,0xF8,0x00,0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xFE,0x00,
+       0xFE,0xC0,0xC0,0xFC,0xC0,0xC0,0xC0,0x00,0x3E,0x60,0xC0,0xCE,0xC6,0x66,0x3E,0x00,
+       0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x7E,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,
+       0x06,0x06,0x06,0x06,0xC6,0xC6,0x7C,0x00,0xC6,0xCC,0xD8,0xF0,0xF8,0xDC,0xCE,0x00,
+       0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0x00,
+       0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,
+       0xFC,0xC6,0xC6,0xC6,0xFC,0xC0,0xC0,0x00,0x7C,0xC6,0xC6,0xC6,0xDE,0xCC,0x7A,0x00,
+       0xFC,0xC6,0xC6,0xCE,0xF8,0xDC,0xCE,0x00,0x78,0xCC,0xC0,0x7C,0x06,0xC6,0x7C,0x00,
+       0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,
+       0xC6,0xC6,0xC6,0xEE,0x7C,0x38,0x10,0x00,0xC6,0xC6,0xD6,0xFE,0xFE,0xEE,0xC6,0x00,
+       0xC6,0xEE,0x3C,0x38,0x7C,0xEE,0xC6,0x00,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x00,
+       0xFE,0x0E,0x1C,0x38,0x70,0xE0,0xFE,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,
+       0x60,0x60,0x30,0x18,0x0C,0x06,0x06,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,
+       0x18,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
+       0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x06,0x3E,0x66,0x66,0x3C,0x00,
+       0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x00,
+       0x06,0x3E,0x66,0x66,0x66,0x66,0x3E,0x00,0x00,0x3C,0x66,0x66,0x7E,0x60,0x3C,0x00,
+       0x1C,0x30,0x78,0x30,0x30,0x30,0x30,0x00,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x3C,
+       0x60,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x00,
+       0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x38,0x60,0x60,0x66,0x6C,0x78,0x6C,0x66,0x00,
+       0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0xEC,0xFE,0xFE,0xFE,0xD6,0xC6,0x00,
+       0x00,0x7C,0x76,0x66,0x66,0x66,0x66,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x00,
+       0x00,0x7C,0x66,0x66,0x66,0x7C,0x60,0x60,0x00,0x3E,0x66,0x66,0x66,0x3E,0x06,0x06,
+       0x00,0x7E,0x70,0x60,0x60,0x60,0x60,0x00,0x00,0x3C,0x60,0x3C,0x06,0x66,0x3C,0x00,
+       0x30,0x78,0x30,0x30,0x30,0x30,0x1C,0x00,0x00,0x66,0x66,0x66,0x66,0x6E,0x3E,0x00,
+       0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0xC6,0xD6,0xFE,0xFE,0x7C,0x6C,0x00,
+       0x00,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00,0x00,0x66,0x66,0x66,0x66,0x3E,0x06,0x3C,
+       0x00,0x7E,0x0C,0x18,0x30,0x60,0x7E,0x00,0x0E,0x18,0x0C,0x38,0x0C,0x18,0x0E,0x00,
+       0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x70,0x18,0x30,0x1C,0x30,0x18,0x70,0x00,
+       0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x10,0x28,0x10,0x54,0xAA,0x44,0x00,0x00,
+};
+
diff --git a/op_gammatool.c b/op_gammatool.c
new file mode 100644 (file)
index 0000000..cda8e01
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2010, Gražvydas Ignotas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the organization nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/fb.h>
+#include <linux/input.h>
+#include <linux/matroxfb.h>
+
+
+#define SPLIT 12
+
+#define DO_RGB(type,d,after,r,g,b) { \
+       int i, u, c, l, div = (w << 8) / SPLIT; \
+       char lines[8][dotsz * w]; \
+       type *dest; \
+       for (dest = (void *)lines[0], i = 0; i < w; i++) { \
+               d = (i * (1 << r) / w) << (g+b); \
+               after; \
+       } \
+       for (dest = (void *)lines[1], i = 0; i < w; i++) { \
+               d = (i * (1 << g) / w) << b; \
+               after; \
+       } \
+       for (dest = (void *)lines[2], i = 0; i < w; i++) { \
+               d = (i * (1 << b) / w); \
+               after; \
+       } \
+       for (dest = (void *)lines[3], i = 0; i < w; i++) { \
+               d = ((i * (1 << r) / w) << (g+b)) | \
+                   ((i * (1 << g) / w) << b) | \
+                   (i * (1 << b) / w); \
+               after; \
+       } \
+\
+       for (dest = (void *)lines[4], i = 0; i < w; i++) { \
+               c = (((i << 8) / div + 1) * div) >> 8; \
+               d = ((c * (1 << r) / w) << (g+b)) | \
+                   ((c * (1 << g) / w) << b) | \
+                   (c * (1 << b) / w); \
+               after; \
+       } \
+       for (dest = (void *)lines[5], i = 0; i < w; i++) { \
+               c = (((i << 8) / div + 1) * div) >> 8; \
+               d = (c * (1 << b) / w); \
+               after; \
+       } \
+       for (dest = (void *)lines[6], i = 0; i < w; i++) { \
+               c = (((i << 8) / div + 1) * div) >> 8; \
+               d = (c * (1 << g) / w) << b; \
+               after; \
+       } \
+       for (dest = (void *)lines[7], i = 0; i < w; i++) { \
+               c = (((i << 8) / div + 1) * div) >> 8; \
+               d = (c * (1 << r) / w) << (g+b); \
+               after; \
+       } \
+\
+       for (u = 0; u < h; u++) { \
+               l = u / (h / 8); \
+               memcpy((char *)ptr + u * dotsz * w, lines[l], dotsz * w); \
+       } \
+}
+
+#include "font.c"
+
+static void text_out(void *fbi, int x, int y, int dotsz, int stride, const char *text)
+{
+       int i, l, v = -1;
+       char *fb;
+
+       fb = (char *)fbi + x * dotsz + y * stride;
+
+       for (i = 0; i < strlen(text); i++)
+       {
+               for (l=0;l<8;l++)
+               {
+                       #define pix(fdmask,add) \
+                               if (fontdata8x8[((text[i])*8)+l]&fdmask) \
+                                       memcpy(fb + l*stride + add*dotsz, &v, dotsz)
+                       pix(0x80,  0);
+                       pix(0x40,  1);
+                       pix(0x20,  2);
+                       pix(0x10,  3);
+                       pix(0x08,  4);
+                       pix(0x04,  5);
+                       pix(0x02,  6);
+                       pix(0x01,  7);
+                       #undef pix
+               }
+               fb += dotsz * 8;
+       }
+}
+
+static void get_config(char *buff, size_t size, int just_dir)
+{
+       char *home;
+
+       home = getenv("HOME");
+       if (home == NULL)
+               home = "";
+       if (just_dir)
+               snprintf(buff, size, "%s/.config", home);
+       else
+               snprintf(buff, size, "%s/.config/op_gammatool", home);
+}
+
+static int do_load(int *gamma)
+{
+       int ret, *g = gamma;
+       char buff[128];
+       FILE *f;
+
+       get_config(buff, sizeof(buff), 0);
+       f = fopen(buff, "r");
+       if (f == NULL)
+               return -1;
+       ret = fscanf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
+               &g[0], &g[1], &g[2], &g[3], &g[4],  &g[5],
+               &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
+       fclose(f);
+
+       return (ret == 12) ? 0 : -1;
+}
+
+static int do_save(const int *gamma)
+{
+       const int *g = gamma;
+       char buff[128];
+       FILE *f;
+       int ret;
+
+       get_config(buff, sizeof(buff), 1);
+       mkdir(buff, 0644);
+       get_config(buff, sizeof(buff), 0);
+       f = fopen(buff, "w");
+       if (f == NULL)
+               return -1;
+       ret = fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
+               g[0], g[1], g[2], g[3], g[4],  g[5],
+               g[6], g[7], g[8], g[9], g[10], g[11]);
+       fclose(f);
+
+       return (ret > 0) ? 0 : -1;
+}
+
+int main(int argc, char *argv[])
+{
+       const char *msg_once = "Start - exit, Y - change bpp, A/B - save/load, "
+                               "hold R for faster tuning";
+       int pressed_up = 0, pressed_down = 0, pressed_r = 0;
+       struct fb_var_screeninfo fbvar;
+       int fbdev, ifd, ret, sel = 0;
+       int i, w, h, dotsz = 0, stride;
+       int gamma[12] = { 0, };
+       char buff[64];
+       FILE *f;
+       void *ptr;
+
+       fbdev = open("/dev/fb0", O_RDWR);
+       if (fbdev == -1) {
+               perror("open(\"/dev/fb0\") failed");
+               return 1;
+       }
+
+       ret = ioctl(fbdev, FBIOGET_VSCREENINFO, &fbvar);
+       if (ret == -1) {
+               perror("ioctl(FBIOGET_FSCREENINFO) failed");
+               return 1;
+       }
+
+       if (argv[1] != NULL) {
+               fbvar.bits_per_pixel = atoi(argv[1]);
+               ret = ioctl(fbdev, FBIOPUT_VSCREENINFO, &fbvar);
+               if (ret == -1)
+               {
+                       perror("ioctl FBIOPUT_VSCREENINFO");
+               }
+       }
+
+       printf("visible resolution: %i %i\n", fbvar.xres, fbvar.yres);
+       printf("virtual resolution: %i %i\n", fbvar.xres_virtual, fbvar.yres_virtual);
+       printf("offset from virtual to visible: %i %i\n", fbvar.xoffset, fbvar.yoffset);
+       printf("bits_per_pixel: %i\n", fbvar.bits_per_pixel);
+
+       ptr = mmap(0, fbvar.xres * fbvar.yres * 4,
+                       PROT_WRITE|PROT_READ, MAP_SHARED, fbdev, 0);
+       if (ptr == MAP_FAILED)
+               ptr = mmap(0, fbvar.xres * fbvar.yres * fbvar.bits_per_pixel / 8,
+                               PROT_WRITE|PROT_READ, MAP_SHARED, fbdev, 0);
+       if (ptr == MAP_FAILED)
+       {
+               perror("mmap(fbptr) failed");
+               return 1;
+       }
+
+       w = fbvar.xres;
+       h = fbvar.yres;
+
+       // search for gpio keys
+       for (ifd = -1, i = 0; ; i++) {
+               snprintf(buff, sizeof(buff), "/dev/input/event%i", i);
+               ifd = open(buff, O_RDONLY | O_NONBLOCK);
+               if (ifd == -1)
+                       break;
+
+               ioctl(ifd, EVIOCGNAME(sizeof(buff)), buff);
+
+               if (strcasestr(buff, "gpio") != NULL)
+                       break;
+               close(ifd);
+       }
+
+       ret = 0;
+       f = fopen("/sys/devices/platform/omap2_mcspi.1/spi1.1/gamma", "r+");
+       if (f != NULL) {
+               int *g = gamma;
+               rewind(f);
+               ret = fscanf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
+                       &g[0], &g[1], &g[2], &g[3], &g[4],  &g[5],
+                       &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
+       }
+
+       if (ret != 12) {
+               fprintf(stderr, "gamma file missing or bad\n");
+               goto out;
+       }
+
+       while (1)
+       {
+               if (f != NULL) {
+                       int *g = gamma;
+                       rewind(f);
+                       fscanf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
+                               &g[0], &g[1], &g[2], &g[3], &g[4],  &g[5],
+                               &g[6], &g[7], &g[8], &g[9], &g[10], &g[11]);
+               }
+
+               //ioctl(fbdev, FBIO_WAITFORVSYNC, &ret);
+               if (fbvar.bits_per_pixel == 16)
+               {
+                       dotsz = 2;
+                       DO_RGB(unsigned short, dest[i],, 5, 6, 5);
+               }
+               else if (fbvar.bits_per_pixel == 24)
+               {
+                       // BGR?
+                       unsigned char *p;
+                       unsigned int d = 0;
+                       dotsz = 3;
+                       DO_RGB(unsigned char, d, p = &dest[i*3]; p[0] = d; p[1] = d >> 8; p[2] = d >> 16, 8, 8, 8);
+               }
+               else if (fbvar.bits_per_pixel == 32)
+               {
+                       dotsz = 4;
+                       DO_RGB(unsigned int, dest[i],, 8, 8, 8);
+               }
+               else
+               {
+                       fprintf(stderr, "unhandled bpp: %d\n", fbvar.bits_per_pixel);
+                       goto out;
+               }
+               stride = dotsz * w;
+
+               snprintf(buff, sizeof(buff), "%dbpp", fbvar.bits_per_pixel);
+               text_out(ptr, 8, 10, dotsz, stride, buff);
+               if (msg_once != NULL) {
+                       text_out(ptr, 80, 10, dotsz, stride, msg_once);
+                       msg_once = NULL;
+               }
+               for (i = 0; i < 12; i++) {
+                       int x = i * w / 12 + 8;
+                       if (i == sel)
+                               text_out(ptr, x, h - 18, dotsz, stride, "____");
+                       snprintf(buff, sizeof(buff), "%d", gamma[i]);
+                       text_out(ptr, x, h - 20, dotsz, stride, buff);
+               }
+
+               // do input
+               if (ifd == -1)
+                       break;
+
+               while (1)
+               {
+                       struct input_event ev;
+                       ret = read(ifd, &ev, sizeof(ev));
+                       if (ret < (int) sizeof(ev)) {
+                               if (errno == EAGAIN || errno == EWOULDBLOCK)
+                                       goto input_no_change;
+
+                               perror("evtest: read error");
+                               goto out;
+                       }
+
+                       if (ev.type != EV_KEY)
+                               continue;
+
+                       switch (ev.code) {
+                       case KEY_LEFT:
+                               if (ev.value)
+                                       sel--;
+                               if (sel < 0)
+                                       sel = 11;
+                               goto input_done;
+                       case KEY_RIGHT:
+                               if (ev.value)
+                                       sel++;
+                               if (sel > 11)
+                                       sel = 0;
+                               goto input_done;
+                       case KEY_UP:
+                               pressed_up = ev.value;
+                               break;
+                       case KEY_DOWN:
+                               pressed_down = ev.value;
+                               break;
+                       case KEY_RIGHTCTRL:
+                       case BTN_TR:
+                               pressed_r = ev.value;
+                               break;
+                       case KEY_PAGEUP:
+                       case BTN_BASE:
+                               if (ev.value) {
+                                       fbvar.bits_per_pixel += 8;
+                                       if (fbvar.bits_per_pixel > 32)
+                                               fbvar.bits_per_pixel = 16;
+                                       ret = ioctl(fbdev, FBIOPUT_VSCREENINFO, &fbvar);
+                                       if (ret == -1)
+                                               perror("ioctl FBIOPUT_VSCREENINFO");
+                               }
+                               goto input_done;
+                       case KEY_END:
+                       case BTN_BASE2:
+                               if (!ev.value)
+                                       break;
+                               if (do_load(gamma) == 0)
+                                       msg_once = "loaded";
+                               else
+                                       msg_once = "load failed";
+                               goto input_done_gamma;
+                       case KEY_HOME:
+                       case BTN_BASE4:
+                               if (!ev.value)
+                                       break;
+                               if (do_save(gamma) == 0)
+                                       msg_once = "saved";
+                               else
+                                       msg_once = "save failed";
+                               goto input_done;
+                       case KEY_LEFTALT:
+                       case BTN_START:
+                               goto out;
+                       case KEY_LEFTCTRL:
+                       case BTN_SELECT:
+                               goto out;
+                       }
+
+input_no_change:
+                       if (pressed_up) {
+                               gamma[sel]++;
+                               if (gamma[sel] >= 1023)
+                                       gamma[sel] = 1023;
+                               if (!pressed_r)
+                                       usleep(30000);
+                               goto input_done_gamma;
+                       }
+                       if (pressed_down) {
+                               gamma[sel]--;
+                               if (gamma[sel] < 0)
+                                       gamma[sel] = 0;
+                               if (!pressed_r)
+                                       usleep(30000);
+                               goto input_done_gamma;
+                       }
+
+                       usleep(10000);
+               }
+
+input_done_gamma:
+               if (f != NULL) {
+                       int *g = gamma;
+                       rewind(f);
+                       fprintf(f, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
+                               g[0], g[1], g[2], g[3], g[4],  g[5],
+                               g[6], g[7], g[8], g[9], g[10], g[11]);
+               }
+input_done:;
+       }
+
+out:
+       munmap(ptr, fbvar.xres * fbvar.yres * fbvar.bits_per_pixel / 8);
+       close(fbdev);
+       if (ifd != -1)
+               close(ifd);
+       return 0;
+}
+
diff --git a/op_runfbapp.c b/op_runfbapp.c
new file mode 100644 (file)
index 0000000..2e480e4
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2010, Gražvydas Ignotas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the organization nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <linux/kd.h>
+
+#define PFX "op_runfbapp: "
+
+static struct termios g_kbd_termios_saved;
+static int g_kbdfd;
+
+static Cursor transparent_cursor(Display *display, Window win)
+{
+       Cursor cursor;
+       Pixmap pix;
+       XColor dummy;
+       char d = 0;
+
+       memset(&dummy, 0, sizeof(dummy));
+       pix = XCreateBitmapFromData(display, win, &d, 1, 1);
+       cursor = XCreatePixmapCursor(display, pix, pix,
+                       &dummy, &dummy, 0, 0);
+       XFreePixmap(display, pix);
+       return cursor;
+}
+
+static void *x11_handler(void *arg)
+{
+       unsigned int display_width, display_height;
+       XSetWindowAttributes attributes;
+       Window win;
+       XEvent report;
+       Display *display;
+       int screen;
+
+       display = XOpenDisplay(NULL);
+       if (display == NULL)
+       {
+               fprintf(stderr, PFX "(not hiding X): Can't open display: %s\n",
+                       XDisplayName(NULL));
+               return NULL;
+       }
+
+       screen = DefaultScreen(display);
+
+       display_width = DisplayWidth(display, screen);
+       display_height = DisplayHeight(display, screen);
+
+       win = XCreateSimpleWindow(display,
+                       RootWindow(display, screen),
+                       0, 0, display_width, display_height, 0,
+                       BlackPixel(display, screen),
+                       BlackPixel(display, screen));
+
+       attributes.override_redirect = True;
+       attributes.cursor = transparent_cursor(display, win);
+       XChangeWindowAttributes(display, win, CWOverrideRedirect | CWCursor, &attributes);
+
+       XSelectInput(display, win, ExposureMask);
+       XMapWindow(display, win);
+       XGrabKeyboard(display, win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
+
+       while (1)
+       {
+               XNextEvent(display, &report);
+
+               if (report.type == Expose)
+                       while (XCheckTypedEvent(display, Expose, &report))
+                               ;
+       }
+
+       return NULL;
+}
+
+static void hidecon_start(void)
+{
+       struct termios kbd_termios;
+       int mode;
+
+       g_kbdfd = open("/dev/tty", O_RDWR);
+       if (g_kbdfd == -1) {
+               perror(PFX "open /dev/tty");
+               return;
+       }
+
+       if (ioctl(g_kbdfd, KDGETMODE, &mode) == -1) {
+               perror(PFX "(not hiding FB): KDGETMODE");
+               goto fail;
+       }
+
+       if (tcgetattr(g_kbdfd, &kbd_termios) == -1) {
+               perror(PFX "tcgetattr");
+               goto fail;
+       }
+
+       g_kbd_termios_saved = kbd_termios;
+       kbd_termios.c_lflag &= ~(ICANON | ECHO); // | ISIG);
+       kbd_termios.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON);
+       kbd_termios.c_cc[VMIN] = 0;
+       kbd_termios.c_cc[VTIME] = 0;
+
+       if (tcsetattr(g_kbdfd, TCSAFLUSH, &kbd_termios) == -1) {
+               perror(PFX "tcsetattr");
+               goto fail;
+       }
+
+       if (ioctl(g_kbdfd, KDSETMODE, KD_GRAPHICS) == -1) {
+               perror(PFX "KDSETMODE KD_GRAPHICS");
+               tcsetattr(g_kbdfd, TCSAFLUSH, &g_kbd_termios_saved);
+               goto fail;
+       }
+
+       return;
+
+fail:
+       close(g_kbdfd);
+       g_kbdfd = -1;
+}
+
+static void hidecon_end(void)
+{
+       if (g_kbdfd < 0)
+               return;
+
+       if (ioctl(g_kbdfd, KDSETMODE, KD_TEXT) == -1)
+               perror(PFX "KDSETMODE KD_TEXT");
+
+       if (tcsetattr(g_kbdfd, TCSAFLUSH, &g_kbd_termios_saved) == -1)
+               perror(PFX "tcsetattr");
+
+       close(g_kbdfd);
+       g_kbdfd = -1;
+}
+
+int main(int argc, char *argv[])
+{
+       pthread_t tid;
+       char *cmd, *p;
+       int len = 0;
+       int ret;
+       int i;
+
+       for (i = 1; i < argc; i++)
+               len += strlen(argv[i]) + 1;
+
+       cmd = malloc(len);
+       if (cmd == NULL)
+       {
+               fprintf(stderr, PFX "OOM\n");
+               return 1;
+       }
+
+       /* rebuild command line for program we launch */
+       for (p = cmd, i = 1; i < argc; i++) {
+               strcpy(p, argv[i]);
+               p += strlen(p);
+
+               if (i < argc - 1)
+                       *p++ = ' ';
+       }
+
+       ret = pthread_create(&tid, NULL, x11_handler, NULL);
+       if (ret != 0) {
+               fprintf(stderr, PFX "pthread_create: %d\n", ret);
+               return 1;
+       }
+       pthread_detach(tid);
+
+       hidecon_start();
+
+       ret = system(cmd);
+       if (ret == -1)
+               perror(PFX "system");
+       free(cmd);
+
+       hidecon_end();
+
+       /* XXX: maybe stop the X thread nicely? */
+
+       return 0;
+}
+
diff --git a/scripts/op_gammatool b/scripts/op_gammatool
new file mode 100755 (executable)
index 0000000..bbc9eaa
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+OLDDEPTH=`fbset | grep geometry | awk '{ print $6 }'`
+
+if [ -n "$DISPLAY" -a "$(id -u)" != "0" ]
+then
+       gksudo ./op_runfbapp ./op_gammatool_bin
+else
+       ./op_runfbapp ./op_gammatool_bin
+fi
+
+fbset -depth $OLDDEPTH