*/
#define _GNU_SOURCE
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "font.c"
+#define array_size(x) (sizeof(x) / sizeof(x[0]))
+
+/* this sucks, but EvilDragon wants it */
+#ifdef VALIDATION
+#define NUB_RANGE_REQ (256-8*3)
+#else
+#define NUB_RANGE_REQ 256
+#endif
+
typedef struct {
int x, y;
int code;
- int active;
+ unsigned int active:1;
+ unsigned int tested:1;
const char *name;
} key_item;
static key_item key_items[] =
{
- { 66, 26, KEY_1, 0, "1" },
- { 133, 26, KEY_2, 0, "2" },
- { 200, 26, KEY_3, 0, "3" },
- { 266, 26, KEY_4, 0, "4" },
- { 333, 26, KEY_5, 0, "5" },
- { 400, 26, KEY_6, 0, "6" },
- { 466, 26, KEY_7, 0, "7" },
- { 533, 26, KEY_8, 0, "8" },
- { 600, 26, KEY_9, 0, "9" },
- { 666, 26, KEY_0, 0, "0" },
- { 733, 26, KEY_BACKSPACE, 0, "DEL" },
+ { 66, 26, KEY_1, 0, 0, "1" },
+ { 133, 26, KEY_2, 0, 0, "2" },
+ { 200, 26, KEY_3, 0, 0, "3" },
+ { 266, 26, KEY_4, 0, 0, "4" },
+ { 333, 26, KEY_5, 0, 0, "5" },
+ { 400, 26, KEY_6, 0, 0, "6" },
+ { 466, 26, KEY_7, 0, 0, "7" },
+ { 533, 26, KEY_8, 0, 0, "8" },
+ { 600, 26, KEY_9, 0, 0, "9" },
+ { 666, 26, KEY_0, 0, 0, "0" },
+ { 733, 26, KEY_BACKSPACE, 0, 0, "DEL" },
//
- { 10, 55, KEY_RIGHTSHIFT,0, "L" },
- { 10, 75, KEY_KPPLUS, 0, "L2" },
- { 758, 55, KEY_RIGHTCTRL, 0, "R" },
- { 758, 75, KEY_KPMINUS, 0, "R2" },
- { 10, 220, KEY_POWER, 0, "POWER" },
- { 10, 240, KEY_COFFEE, 0, "HOLD" },
+ { 10, 55, KEY_RIGHTSHIFT,0, 0, "L" },
+ { 10, 75, KEY_KPPLUS, 0, 0, "L2" },
+ { 758, 55, KEY_RIGHTCTRL, 0, 0, "R" },
+ { 758, 75, KEY_KPMINUS, 0, 0, "R2" },
+ { 10, 220, KEY_POWER, 0, 0, "POWER" },
+ { 10, 240, KEY_COFFEE, 0, 0, "HOLD" },
//
- { 130, 94, KEY_UP, 0, "U" },
- { 80, 163, KEY_LEFT, 0, "L" },
- { 180, 163, KEY_RIGHT, 0, "R" },
- { 130, 232, KEY_DOWN, 0, "D" },
- { 376, 94, KEY_LEFTALT,0, "ALT" },
- { 368, 163, KEY_LEFTCTRL,0,"CTRL" },
- { 368, 232, KEY_MENU, 0, "MENU" },
- { 700, 94, KEY_PAGEUP, 0, "1" },
- { 650, 163, KEY_HOME, 0, "4" },
- { 750, 163, KEY_END, 0, "2" },
- { 700, 232, KEY_PAGEDOWN,0, "3" },
+ { 130, 94, KEY_UP, 0, 0, "U" },
+ { 80, 163, KEY_LEFT, 0, 0, "L" },
+ { 180, 163, KEY_RIGHT, 0, 0, "R" },
+ { 130, 232, KEY_DOWN, 0, 0, "D" },
+ { 376, 94, KEY_LEFTALT,0, 0, "ALT" },
+ { 368, 163, KEY_LEFTCTRL,0,0, "CTRL" },
+ { 368, 232, KEY_MENU, 0, 0, "MENU" },
+ { 700, 94, KEY_PAGEUP, 0, 0, "Y" },
+ { 650, 163, KEY_HOME, 0, 0, "A" },
+ { 750, 163, KEY_END, 0, 0, "B" },
+ { 700, 232, KEY_PAGEDOWN,0,0, "X" },
//
- { 92, 300, KEY_Q, 0, "Q" },
- { 158, 300, KEY_W, 0, "W" },
- { 225, 300, KEY_E, 0, "E" },
- { 292, 300, KEY_R, 0, "R" },
- { 358, 300, KEY_T, 0, "T" },
- { 425, 300, KEY_Y, 0, "Y" },
- { 492, 300, KEY_U, 0, "U" },
- { 558, 300, KEY_I, 0, "I" },
- { 625, 300, KEY_O, 0, "O" },
- { 692, 300, KEY_P, 0, "P" },
+ { 92, 300, KEY_Q, 0, 0, "Q" },
+ { 158, 300, KEY_W, 0, 0, "W" },
+ { 225, 300, KEY_E, 0, 0, "E" },
+ { 292, 300, KEY_R, 0, 0, "R" },
+ { 358, 300, KEY_T, 0, 0, "T" },
+ { 425, 300, KEY_Y, 0, 0, "Y" },
+ { 492, 300, KEY_U, 0, 0, "U" },
+ { 558, 300, KEY_I, 0, 0, "I" },
+ { 625, 300, KEY_O, 0, 0, "O" },
+ { 692, 300, KEY_P, 0, 0, "P" },
//
- { 30, 369, KEY_LEFTSHIFT, 0, "SHIFT" },
- { 133, 369, KEY_A, 0, "A" },
- { 200, 369, KEY_S, 0, "S" },
- { 266, 369, KEY_D, 0, "D" },
- { 333, 369, KEY_F, 0, "F" },
- { 400, 369, KEY_G, 0, "G" },
- { 466, 369, KEY_H, 0, "H" },
- { 533, 369, KEY_J, 0, "J" },
- { 600, 369, KEY_K, 0, "K" },
- { 666, 369, KEY_L, 0, "L" },
- { 710, 369, KEY_ENTER, 0, "ENTER" },
+ { 30, 369, KEY_LEFTSHIFT, 0, 0, "SHIFT" },
+ { 133, 369, KEY_A, 0, 0, "A" },
+ { 200, 369, KEY_S, 0, 0, "S" },
+ { 266, 369, KEY_D, 0, 0, "D" },
+ { 333, 369, KEY_F, 0, 0, "F" },
+ { 400, 369, KEY_G, 0, 0, "G" },
+ { 466, 369, KEY_H, 0, 0, "H" },
+ { 533, 369, KEY_J, 0, 0, "J" },
+ { 600, 369, KEY_K, 0, 0, "K" },
+ { 666, 369, KEY_L, 0, 0, "L" },
+ { 710, 369, KEY_ENTER, 0, 0, "ENTER" },
//
- { 25, 437, KEY_COMMA, 0, "," },
- { 92, 437, KEY_DOT, 0, "." },
- { 158, 437, KEY_Z, 0, "Z" },
- { 225, 437, KEY_X, 0, "X" },
- { 292, 437, KEY_C, 0, "C" },
- { 358, 437, KEY_V, 0, "V" },
- { 425, 437, KEY_B, 0, "B" },
- { 492, 437, KEY_N, 0, "N" },
- { 558, 437, KEY_M, 0, "M" },
- { 625, 437, KEY_SPACE, 0, "SPACE" },
- { 758, 437, KEY_FN, 0, "Fn" },
+ { 25, 437, KEY_COMMA, 0, 0, "," },
+ { 92, 437, KEY_DOT, 0, 0, "." },
+ { 158, 437, KEY_Z, 0, 0, "Z" },
+ { 225, 437, KEY_X, 0, 0, "X" },
+ { 292, 437, KEY_C, 0, 0, "C" },
+ { 358, 437, KEY_V, 0, 0, "V" },
+ { 425, 437, KEY_B, 0, 0, "B" },
+ { 492, 437, KEY_N, 0, 0, "N" },
+ { 558, 437, KEY_M, 0, 0, "M" },
+ { 625, 437, KEY_SPACE, 0, 0, "SPACE" },
+ { 758, 437, KEY_FN, 0, 0, "Fn" },
};
#define KI_COUNT (sizeof(key_items) / sizeof(key_items[0]))
-static int ts_old_x = 0, ts_old_y = 0;
-static int lid_closed = 0;
+static int nub_range_hit, all_btns_tested, lid_tested, ts_tested;
+static int ts_old_x, ts_old_y;
+static int lid_closed;
static void draw_ts_cross(unsigned short *fb, unsigned short col, int x, int y)
{
if (x >= 0 && x < 800)
for (y1 = y - 5, i = 0; i < 11; i++, y1++)
if (y1 >= 0 && y1 < 480) fb[y1 * 800 + x] = col;
-
+
+ if (x != ts_old_x && y != ts_old_y)
+ ts_tested = 1;
+
ts_old_x = x;
ts_old_y = y;
}
static void redraw_nubs(unsigned short *fb, int x1, int y1, int x2, int y2)
{
char buff[32];
- int y;
+ int fill = 0, y;
fb += 90*800;
+ if (nub_range_hit == 0xff && all_btns_tested && lid_tested && ts_tested)
+ fill = 3;
+
// clear areas
for (y = 0; y < 140; y++) {
- memset(fb + 800*y + 200, 0, (64+8)*2*2);
- memset(fb + 800*y + 450, 0, (64+8)*2*2);
+ memset(fb + 800*y + 200, fill, (64+8)*2*2);
+ memset(fb + 800*y + 450, fill, (64+8)*2*2);
}
text_out16(fb + 200, 32*2 + x1/8, 32*2 + y1/8, 0x001f, "@");
text_out16(fb + 450, 32*2 + x2/8, 32*2 + y2/8, 0x001f, "@");
- snprintf(buff, sizeof(buff), "%2i, %2i", x1/8, y1/8);
- text_out16_small(fb, 245, 130, 0x7bef, buff);
- snprintf(buff, sizeof(buff), "%2i, %2i", x2/8, y2/8);
- text_out16_small(fb, 495, 130, 0x7bef, buff);
+ if (x1 <= -NUB_RANGE_REQ) nub_range_hit |= 0x01;
+ if (x1 >= NUB_RANGE_REQ) nub_range_hit |= 0x02;
+ if (y1 <= -NUB_RANGE_REQ) nub_range_hit |= 0x04;
+ if (y1 >= NUB_RANGE_REQ) nub_range_hit |= 0x08;
+ if (x2 <= -NUB_RANGE_REQ) nub_range_hit |= 0x10;
+ if (x2 >= NUB_RANGE_REQ) nub_range_hit |= 0x20;
+ if (y2 <= -NUB_RANGE_REQ) nub_range_hit |= 0x40;
+ if (y2 >= NUB_RANGE_REQ) nub_range_hit |= 0x80;
+
+ snprintf(buff, sizeof(buff), "%3i", x1/8);
+ text_out16_small(fb, 235, 130, (nub_range_hit & 0x03) == 0x03 ? 0xce6f : 0x7bef, buff);
+ snprintf(buff, sizeof(buff), "%3i", y1/8);
+ text_out16_small(fb, 270, 130, (nub_range_hit & 0x0c) == 0x0c ? 0xce6f : 0x7bef, buff);
+
+ snprintf(buff, sizeof(buff), "%3i", x2/8);
+ text_out16_small(fb, 485, 130, (nub_range_hit & 0x30) == 0x30 ? 0xce6f : 0x7bef, buff);
+ snprintf(buff, sizeof(buff), "%3i", y2/8);
+ text_out16_small(fb, 520, 130, (nub_range_hit & 0xc0) == 0xc0 ? 0xce6f : 0x7bef, buff);
}
static void redraw_keys_lid(unsigned short *fb)
key = &key_items[i];
text_out16(fb, key->x, key->y,
- key->active ? 0x07e0 : 0x7bef, key->name);
+ key->active ? 0x07e0 : (key->tested ? 0xce6f : 0x7bef),
+ key->name);
}
- text_out16(fb, 10, 260, lid_closed ? 0x07e0 : 0x7bef, "LID");
+ text_out16(fb, 10, 260, lid_closed ? 0x07e0 : (lid_tested ? 0xce6f : 0x7bef), "LID");
}
-static void setkey(int code, int val)
+static void set_key(int code, int val)
{
key_item *key = NULL;
int i;
}
else
{
- key->active = val;
+ key->active = !!val;
+ key->tested |= !!val;
printf("%c %s\n", val ? '+' : '-', key->name);
}
+
+ if (all_btns_tested)
+ return;
+
+ for (i = 0; i < KI_COUNT; i++)
+ {
+ if (key_items[i].code == KEY_MENU)
+ continue;
+ if (key_items[i].code == KEY_KPPLUS || key_items[i].code == KEY_KPMINUS)
+ continue;
+ if (!key_items[i].tested)
+ break;
+ }
+
+ if (i == KI_COUNT)
+ all_btns_tested = 1;
+}
+
+/* sound test */
+#include <sys/soundcard.h>
+#include <pthread.h>
+
+static int snd_test_l, snd_test_r, snd_test_quit;
+static pthread_cond_t snd_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t snd_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void *sound_thread(void *arg)
+{
+ int i, ret, randfd, dspfd;
+ int frag, bits, stereo, rate;
+ short buf[8*1024];//2*22050 / 10];
+
+ randfd = open("/dev/urandom", O_RDONLY);
+ if (randfd == -1) {
+ perror("open(\"/dev/urandom\")");
+ return NULL;
+ }
+
+ dspfd = open("/dev/dsp", O_WRONLY);
+ if (dspfd == -1) {
+ perror("open(\"/dev/dsp\")");
+ close(randfd);
+ return NULL;
+ }
+
+ frag = (2 << 16) | 13;
+ ret = ioctl(dspfd, SNDCTL_DSP_SETFRAGMENT, &frag);
+ if (ret < 0)
+ perror("SNDCTL_DSP_SETFRAGMENT");
+
+ stereo = 1; bits = 16; rate = 22050;
+ ret = ioctl(dspfd, SNDCTL_DSP_STEREO, &stereo);
+ if (ret == 0)
+ ret = ioctl(dspfd, SNDCTL_DSP_SETFMT, &bits);
+ if (ret == 0)
+ ret = ioctl(dspfd, SNDCTL_DSP_SPEED, &rate);
+ if (ret < 0)
+ perror("failed to set audio format");
+
+ while (1) {
+ pthread_mutex_lock(&snd_mutex);
+ if (!snd_test_l && !snd_test_r)
+ pthread_cond_wait(&snd_cond, &snd_mutex);
+ pthread_mutex_unlock(&snd_mutex);
+
+ if (snd_test_quit)
+ break;
+
+ ret = read(randfd, buf, sizeof(buf));
+ if (ret == -1) {
+ perror("urandom read");
+ break;
+ }
+
+ if (!snd_test_l)
+ for (i = 0; i < array_size(buf) / 2; i++)
+ buf[i * 2] = 0;
+ if (!snd_test_r)
+ for (i = 0; i < array_size(buf) / 2; i++)
+ buf[i * 2 + 1] = 0;
+
+ ret = write(dspfd, buf, sizeof(buf));
+ if (ret == -1) {
+ perror("dsp write");
+ break;
+ }
+ }
+
+ close(randfd);
+ close(dspfd);
+
+ return NULL;
+}
+
+static void sound_init(void)
+{
+ pthread_t tid;
+ int ret;
+
+ ret = pthread_create(&tid, NULL, sound_thread, NULL);
+ if (ret != 0) {
+ fprintf(stderr, "pthread_create sound_thread: %d\n", ret);
+ return;
+ }
+ pthread_detach(tid);
+}
+
+static void sound_do(int l, int r)
+{
+ pthread_mutex_lock(&snd_mutex);
+ snd_test_l = l;
+ snd_test_r = r;
+ if (l || r || snd_test_quit)
+ pthread_cond_signal(&snd_cond);
+ pthread_mutex_unlock(&snd_mutex);
}
enum {
int nubx[2] = {0,0}, nuby[2] = {0,0};
int pressed_l = 0, pressed_r = 0;
struct tsdev *ts = NULL;
+ int retval = 0;
fbdev = open("/dev/fb0", O_RDWR);
if (fbdev == -1)
memset(screen, 0, 800*480*2);
+ sound_init();
+
for (id = 0; ; id++)
{
char fname[64];
ioctl(fd, EVIOCGNAME(sizeof(name)), name);
- if (strcasestr(name, "power") != NULL)
+ if (strcasestr(name, "power") != NULL || strcasestr(name, "pwrbutton") != NULL)
{
ifd[DEV_PWRBTN] = fd;
}
if (ifd[DEV_PWRBTN] == -1) printf("Warning: couldn't find pwrbutton device\n");
if (ifd[DEV_KEYPAD] == -1) printf("Warning: couldn't find keypad device\n");
- if (ifd[DEV_BUTTONS] == -1) printf("Warning: couldn't find button device\n");
if (ifd[DEV_TS] == -1) printf("Warning: couldn't find touchscreen device\n");
if (ifd[DEV_LNUB] == -1) printf("Warning: couldn't find nub1 device\n");
if (ifd[DEV_RNUB] == -1) printf("Warning: couldn't find nub2 device\n");
+ if (ifd[DEV_BUTTONS] == -1) {
+ printf("Error: couldn't find button device\n");
+ /* buttons needed to exit this, so bail out */
+ retval = -1;
+ goto end;
+ }
+#ifdef VALIDATION
+ int early_leave_attempt = 0;
+ text_out16_small(screen, 220, 3, 0x7bef,
+ "press menu/pandora to exit");
+#else
text_out16_small(screen, 320, 3, 0x7bef, "Press L+R to exit");
+#endif
+#ifdef VALIDATION
+ while (1)
+#else
while (!pressed_l || !pressed_r)
+#endif
{
struct input_event ev[64];
int fd = -1, rd, which, ret;
fd_set fdset;
+#ifdef VALIDATION
+ if (early_leave_attempt > 1) {
+ char buff[128];
+ snprintf(buff, sizeof(buff), "not everything tested (%s%s%s%s), L+R to override",
+ nub_range_hit == 0xff ? "" : "nubs", all_btns_tested ? "" : " buttons",
+ lid_tested ? "" : " lid_switch", ts_tested ? "" : " touchscreen");
+ memset(screen, 0, 800*12*2);
+ if (nub_range_hit == 0xff && all_btns_tested && lid_tested && ts_tested)
+ text_out16_small(screen, 220, 3, 0x07c0,
+ "press menu/pandora to exit");
+ else
+ text_out16_small(screen, 4, 3, 0xf800, buff);
+ }
+#endif
draw_ts_cross(screen, 0x0000, ts_old_x, ts_old_y);
redraw_keys_lid(screen);
redraw_nubs(screen, nubx[0], nuby[0], nubx[1], nuby[1]);
case EV_SYN:
break;
case EV_KEY:
- setkey(ev[i].code, ev[i].value);
+ set_key(ev[i].code, ev[i].value);
+
if (ev[i].code == KEY_RIGHTSHIFT)
pressed_l = !!ev[i].value;
if (ev[i].code == KEY_RIGHTCTRL)
pressed_r = !!ev[i].value;
+#ifdef VALIDATION
+ if (ev[i].code == KEY_MENU && !!ev[i].value) {
+ if (nub_range_hit == 0xff && all_btns_tested && lid_tested && ts_tested)
+ goto end;
+ if (pressed_l && pressed_r) {
+ retval = 1;
+ goto end;
+ }
+ early_leave_attempt++;
+ }
+#endif
+ if (ev[i].code == KEY_LEFT)
+ sound_do(!!ev[i].value, snd_test_r);
+ if (ev[i].code == KEY_RIGHT)
+ sound_do(snd_test_l, !!ev[i].value);
break;
case EV_ABS:
which = (fd == ifd[DEV_LNUB]) ? 0 : 1;
printf("unexpected EV_ABS code: %i\n", ev[i].code);
break;
case EV_SW:
- if (ev[i].code == SW_LID)
+ if (ev[i].code == SW_LID) {
lid_closed = ev[i].value;
+ lid_tested |= ev[i].value;
+ }
else
printf("unexpected EV_SW code: %i\n", ev[i].code);
break;
}
}
+ snd_test_quit = 1;
+ sound_do(0, 0);
end:
if (ts != NULL)
close(ifd[i]);
munmap(screen, 800*480*2);
close(fbdev);
- return 0;
+ return retval;
}