--- /dev/null
+/* 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,
+};
+
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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;
+}
+