2 * Copyright (c) 2010, GraÅžvydas Ignotas
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.
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.
31 #include <sys/types.h>
36 #include <linux/input.h>
41 #define array_size(x) (sizeof(x) / sizeof(x[0]))
43 /* this sucks, but EvilDragon wants it */
45 #define NUB_RANGE_REQ (256-8*3)
47 #define NUB_RANGE_REQ 256
53 unsigned int active:1;
54 unsigned int tested:1;
58 static key_item key_items[] =
60 { 66, 26, KEY_1, 0, 0, "1" },
61 { 133, 26, KEY_2, 0, 0, "2" },
62 { 200, 26, KEY_3, 0, 0, "3" },
63 { 266, 26, KEY_4, 0, 0, "4" },
64 { 333, 26, KEY_5, 0, 0, "5" },
65 { 400, 26, KEY_6, 0, 0, "6" },
66 { 466, 26, KEY_7, 0, 0, "7" },
67 { 533, 26, KEY_8, 0, 0, "8" },
68 { 600, 26, KEY_9, 0, 0, "9" },
69 { 666, 26, KEY_0, 0, 0, "0" },
70 { 733, 26, KEY_BACKSPACE, 0, 0, "DEL" },
72 { 10, 55, KEY_RIGHTSHIFT,0, 0, "L" },
73 { 10, 75, KEY_KPPLUS, 0, 0, "L2" },
74 { 758, 55, KEY_RIGHTCTRL, 0, 0, "R" },
75 { 758, 75, KEY_KPMINUS, 0, 0, "R2" },
76 { 10, 220, KEY_POWER, 0, 0, "POWER" },
77 { 10, 240, KEY_COFFEE, 0, 0, "HOLD" },
79 { 130, 94, KEY_UP, 0, 0, "U" },
80 { 80, 163, KEY_LEFT, 0, 0, "L" },
81 { 180, 163, KEY_RIGHT, 0, 0, "R" },
82 { 130, 232, KEY_DOWN, 0, 0, "D" },
83 { 376, 94, KEY_LEFTALT,0, 0, "ALT" },
84 { 368, 163, KEY_LEFTCTRL,0,0, "CTRL" },
85 { 368, 232, KEY_MENU, 0, 0, "MENU" },
86 { 700, 94, KEY_PAGEUP, 0, 0, "Y" },
87 { 650, 163, KEY_HOME, 0, 0, "A" },
88 { 750, 163, KEY_END, 0, 0, "B" },
89 { 700, 232, KEY_PAGEDOWN,0,0, "X" },
91 { 92, 300, KEY_Q, 0, 0, "Q" },
92 { 158, 300, KEY_W, 0, 0, "W" },
93 { 225, 300, KEY_E, 0, 0, "E" },
94 { 292, 300, KEY_R, 0, 0, "R" },
95 { 358, 300, KEY_T, 0, 0, "T" },
96 { 425, 300, KEY_Y, 0, 0, "Y" },
97 { 492, 300, KEY_U, 0, 0, "U" },
98 { 558, 300, KEY_I, 0, 0, "I" },
99 { 625, 300, KEY_O, 0, 0, "O" },
100 { 692, 300, KEY_P, 0, 0, "P" },
102 { 30, 369, KEY_LEFTSHIFT, 0, 0, "SHIFT" },
103 { 133, 369, KEY_A, 0, 0, "A" },
104 { 200, 369, KEY_S, 0, 0, "S" },
105 { 266, 369, KEY_D, 0, 0, "D" },
106 { 333, 369, KEY_F, 0, 0, "F" },
107 { 400, 369, KEY_G, 0, 0, "G" },
108 { 466, 369, KEY_H, 0, 0, "H" },
109 { 533, 369, KEY_J, 0, 0, "J" },
110 { 600, 369, KEY_K, 0, 0, "K" },
111 { 666, 369, KEY_L, 0, 0, "L" },
112 { 710, 369, KEY_ENTER, 0, 0, "ENTER" },
114 { 25, 437, KEY_COMMA, 0, 0, "," },
115 { 92, 437, KEY_DOT, 0, 0, "." },
116 { 158, 437, KEY_Z, 0, 0, "Z" },
117 { 225, 437, KEY_X, 0, 0, "X" },
118 { 292, 437, KEY_C, 0, 0, "C" },
119 { 358, 437, KEY_V, 0, 0, "V" },
120 { 425, 437, KEY_B, 0, 0, "B" },
121 { 492, 437, KEY_N, 0, 0, "N" },
122 { 558, 437, KEY_M, 0, 0, "M" },
123 { 625, 437, KEY_SPACE, 0, 0, "SPACE" },
124 { 758, 437, KEY_FN, 0, 0, "Fn" },
127 #define KI_COUNT (sizeof(key_items) / sizeof(key_items[0]))
129 static int nub_range_hit, all_btns_tested, lid_tested, ts_tested;
130 static int ts_old_x, ts_old_y;
131 static int lid_closed;
133 static void draw_ts_cross(unsigned short *fb, unsigned short col, int x, int y)
137 if (y >= 0 && y < 480)
138 for (x1 = x - 5, i = 0; i < 11; i++, x1++)
139 if (x1 >= 0 && x1 < 800) fb[y * 800 + x1] = col;
141 if (x >= 0 && x < 800)
142 for (y1 = y - 5, i = 0; i < 11; i++, y1++)
143 if (y1 >= 0 && y1 < 480) fb[y1 * 800 + x] = col;
145 if (x != ts_old_x && y != ts_old_y)
152 static void text_out16(unsigned short *fb, int x, int y, unsigned short col, const char *text)
158 for (i = 0; i < strlen(text); i++)
162 #define pix(fdmask,add) \
163 if (fontdata8x8[((text[i])*8)+l]&fdmask) \
164 fb[l*2*800+add]=fb[l*2*800+add+1]=fb[l*2*800+800+add]=fb[l*2*800+800+add+1]=col
179 static void text_out16_small(unsigned short *fb, int x, int y, unsigned short col, const char *text)
185 for (i = 0; i < strlen(text); i++)
189 #define pix(fdmask,add) \
190 if (fontdata8x8[((text[i])*8)+l]&fdmask) \
191 fb[l*800+add]=fb[l*800+800+add]=col
206 static void redraw_nubs(unsigned short *fb, int x1, int y1, int x2, int y2)
213 if (nub_range_hit == 0xff && all_btns_tested && lid_tested && ts_tested)
217 for (y = 0; y < 140; y++) {
218 memset(fb + 800*y + 200, fill, (64+8)*2*2);
219 memset(fb + 800*y + 450, fill, (64+8)*2*2);
222 text_out16(fb + 200, 32*2 + x1/8, 32*2 + y1/8, 0x001f, "@");
223 text_out16(fb + 450, 32*2 + x2/8, 32*2 + y2/8, 0x001f, "@");
225 if (x1 <= -NUB_RANGE_REQ) nub_range_hit |= 0x01;
226 if (x1 >= NUB_RANGE_REQ) nub_range_hit |= 0x02;
227 if (y1 <= -NUB_RANGE_REQ) nub_range_hit |= 0x04;
228 if (y1 >= NUB_RANGE_REQ) nub_range_hit |= 0x08;
229 if (x2 <= -NUB_RANGE_REQ) nub_range_hit |= 0x10;
230 if (x2 >= NUB_RANGE_REQ) nub_range_hit |= 0x20;
231 if (y2 <= -NUB_RANGE_REQ) nub_range_hit |= 0x40;
232 if (y2 >= NUB_RANGE_REQ) nub_range_hit |= 0x80;
234 snprintf(buff, sizeof(buff), "%3i", x1/8);
235 text_out16_small(fb, 235, 130, (nub_range_hit & 0x03) == 0x03 ? 0xce6f : 0x7bef, buff);
236 snprintf(buff, sizeof(buff), "%3i", y1/8);
237 text_out16_small(fb, 270, 130, (nub_range_hit & 0x0c) == 0x0c ? 0xce6f : 0x7bef, buff);
239 snprintf(buff, sizeof(buff), "%3i", x2/8);
240 text_out16_small(fb, 485, 130, (nub_range_hit & 0x30) == 0x30 ? 0xce6f : 0x7bef, buff);
241 snprintf(buff, sizeof(buff), "%3i", y2/8);
242 text_out16_small(fb, 520, 130, (nub_range_hit & 0xc0) == 0xc0 ? 0xce6f : 0x7bef, buff);
245 static void redraw_keys_lid(unsigned short *fb)
250 for (i = 0; i < KI_COUNT; i++)
254 text_out16(fb, key->x, key->y,
255 key->active ? 0x07e0 : (key->tested ? 0xce6f : 0x7bef),
259 text_out16(fb, 10, 260, lid_closed ? 0x07e0 : (lid_tested ? 0xce6f : 0x7bef), "LID");
262 static void set_key(int code, int val)
264 key_item *key = NULL;
267 for (i = 0; i < KI_COUNT; i++)
269 if (key_items[i].code == code)
278 printf("%c unexpected key? (%i)\n", val ? '+' : '-', code);
283 key->tested |= !!val;
284 printf("%c %s\n", val ? '+' : '-', key->name);
290 for (i = 0; i < KI_COUNT; i++)
292 if (key_items[i].code == KEY_MENU)
294 if (key_items[i].code == KEY_KPPLUS || key_items[i].code == KEY_KPMINUS)
296 if (!key_items[i].tested)
305 #include <sys/soundcard.h>
308 static int snd_test_l, snd_test_r, snd_test_quit;
309 static pthread_cond_t snd_cond = PTHREAD_COND_INITIALIZER;
310 static pthread_mutex_t snd_mutex = PTHREAD_MUTEX_INITIALIZER;
312 static void *sound_thread(void *arg)
314 int i, ret, randfd, dspfd;
315 int frag, bits, stereo, rate;
316 short buf[8*1024];//2*22050 / 10];
318 randfd = open("/dev/urandom", O_RDONLY);
320 perror("open(\"/dev/urandom\")");
324 dspfd = open("/dev/dsp", O_WRONLY);
326 perror("open(\"/dev/dsp\")");
331 frag = (2 << 16) | 13;
332 ret = ioctl(dspfd, SNDCTL_DSP_SETFRAGMENT, &frag);
334 perror("SNDCTL_DSP_SETFRAGMENT");
336 stereo = 1; bits = 16; rate = 22050;
337 ret = ioctl(dspfd, SNDCTL_DSP_STEREO, &stereo);
339 ret = ioctl(dspfd, SNDCTL_DSP_SETFMT, &bits);
341 ret = ioctl(dspfd, SNDCTL_DSP_SPEED, &rate);
343 perror("failed to set audio format");
346 pthread_mutex_lock(&snd_mutex);
347 if (!snd_test_l && !snd_test_r)
348 pthread_cond_wait(&snd_cond, &snd_mutex);
349 pthread_mutex_unlock(&snd_mutex);
354 ret = read(randfd, buf, sizeof(buf));
356 perror("urandom read");
361 for (i = 0; i < array_size(buf) / 2; i++)
364 for (i = 0; i < array_size(buf) / 2; i++)
367 ret = write(dspfd, buf, sizeof(buf));
380 static void sound_init(void)
385 ret = pthread_create(&tid, NULL, sound_thread, NULL);
387 fprintf(stderr, "pthread_create sound_thread: %d\n", ret);
393 static void sound_do(int l, int r)
395 pthread_mutex_lock(&snd_mutex);
398 if (l || r || snd_test_quit)
399 pthread_cond_signal(&snd_cond);
400 pthread_mutex_unlock(&snd_mutex);
413 int main(int argc, char *argv[])
415 unsigned short *screen;
416 int fbdev, ifd[DEVS_TOTAL] = { -1, -1, -1, -1, -1, -1 };
417 int i, id, imaxfd = 0, ts_x = 0, ts_y = 0;
418 int nubx[2] = {0,0}, nuby[2] = {0,0};
419 int pressed_l = 0, pressed_r = 0;
420 struct tsdev *ts = NULL;
423 fbdev = open("/dev/fb0", O_RDWR);
426 perror("open(\"/dev/fb0\") failed");
430 screen = mmap(0, 800*480*2, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev, 0);
431 if (screen == MAP_FAILED)
433 perror("mmap(fbptr) failed");
437 memset(screen, 0, 800*480*2);
444 char name[256] = { 0, };
447 snprintf(fname, sizeof(fname), "/dev/input/event%i", id);
448 fd = open(fname, O_RDONLY);
454 ioctl(fd, EVIOCGNAME(sizeof(name)), name);
456 if (strcasestr(name, "power") != NULL || strcasestr(name, "pwrbutton") != NULL)
458 ifd[DEV_PWRBTN] = fd;
460 else if (strcasestr(name, "keypad") != NULL)
462 ifd[DEV_KEYPAD] = fd;
464 else if (strcmp(name, "gpio-keys") == 0)
466 ifd[DEV_BUTTONS] = fd;
468 else if (strcasestr(name, "touchscreen") != NULL)
471 ts = ts_open(fname, 0);
482 ifd[DEV_TS] = ts_fd(ts);
484 else if (strcmp(name, "nub0") == 0)
488 else if (strcmp(name, "nub1") == 0)
494 printf("skipping \"%s\"\n", name);
498 if (imaxfd < fd) imaxfd = fd;
501 if (ifd[DEV_PWRBTN] == -1) printf("Warning: couldn't find pwrbutton device\n");
502 if (ifd[DEV_KEYPAD] == -1) printf("Warning: couldn't find keypad device\n");
503 if (ifd[DEV_TS] == -1) printf("Warning: couldn't find touchscreen device\n");
504 if (ifd[DEV_LNUB] == -1) printf("Warning: couldn't find nub1 device\n");
505 if (ifd[DEV_RNUB] == -1) printf("Warning: couldn't find nub2 device\n");
506 if (ifd[DEV_BUTTONS] == -1) {
507 printf("Error: couldn't find button device\n");
508 /* buttons needed to exit this, so bail out */
514 int early_leave_attempt = 0;
515 text_out16_small(screen, 220, 3, 0x7bef,
516 "press menu/pandora to exit");
518 text_out16_small(screen, 320, 3, 0x7bef, "Press L+R to exit");
524 while (!pressed_l || !pressed_r)
527 struct input_event ev[64];
528 int fd = -1, rd, which, ret;
532 if (early_leave_attempt > 1) {
534 snprintf(buff, sizeof(buff), "not everything tested (%s%s%s%s), L+R to override",
535 nub_range_hit == 0xff ? "" : "nubs", all_btns_tested ? "" : " buttons",
536 lid_tested ? "" : " lid_switch", ts_tested ? "" : " touchscreen");
537 memset(screen, 0, 800*12*2);
538 if (nub_range_hit == 0xff && all_btns_tested && lid_tested && ts_tested)
539 text_out16_small(screen, 220, 3, 0x07c0,
540 "press menu/pandora to exit");
542 text_out16_small(screen, 4, 3, 0xf800, buff);
545 draw_ts_cross(screen, 0x0000, ts_old_x, ts_old_y);
546 redraw_keys_lid(screen);
547 redraw_nubs(screen, nubx[0], nuby[0], nubx[1], nuby[1]);
548 draw_ts_cross(screen, 0xf800, ts_x, ts_y);
551 for (i = 0; i < DEVS_TOTAL; i++)
553 FD_SET(ifd[i], &fdset);
555 ret = select(imaxfd + 1, &fdset, NULL, NULL, NULL);
562 for (i = 0; i < DEVS_TOTAL; i++)
563 if (ifd[i] != -1 && FD_ISSET(ifd[i], &fdset))
567 if (fd == ifd[DEV_TS])
569 struct ts_sample samp;
571 ret = ts_read(ts, &samp, 1);
580 ts_x = samp.x; ts_y = samp.y;
581 //printf("ts: %6d %6d %6d\n", samp.x, samp.y, samp.pressure);
585 /* buttons or keypad */
586 rd = read(fd, ev, sizeof(ev));
587 if (rd < (int) sizeof(ev[0])) {
588 perror("\nevtest: error reading");
592 for (i = 0; i < rd / sizeof(ev[0]); i++)
594 switch (ev[i].type) {
598 set_key(ev[i].code, ev[i].value);
600 if (ev[i].code == KEY_RIGHTSHIFT)
601 pressed_l = !!ev[i].value;
602 if (ev[i].code == KEY_RIGHTCTRL)
603 pressed_r = !!ev[i].value;
605 if (ev[i].code == KEY_MENU && !!ev[i].value) {
606 if (nub_range_hit == 0xff && all_btns_tested && lid_tested && ts_tested)
608 if (pressed_l && pressed_r) {
612 early_leave_attempt++;
615 if (ev[i].code == KEY_LEFT)
616 sound_do(!!ev[i].value, snd_test_r);
617 if (ev[i].code == KEY_RIGHT)
618 sound_do(snd_test_l, !!ev[i].value);
621 which = (fd == ifd[DEV_LNUB]) ? 0 : 1;
622 if (ev[i].code == ABS_X)
623 nubx[which] = ev[i].value;
624 else if (ev[i].code == ABS_Y)
625 nuby[which] = ev[i].value;
627 printf("unexpected EV_ABS code: %i\n", ev[i].code);
630 if (ev[i].code == SW_LID) {
631 lid_closed = ev[i].value;
632 lid_tested |= ev[i].value;
635 printf("unexpected EV_SW code: %i\n", ev[i].code);
638 if (ev[i].code == MSC_SCAN)
642 printf("unexpected event: type %i, code %d\n", ev[i].type, ev[i].code);
654 for (i = 0; i < DEVS_TOTAL; i++)
655 if (i != DEV_TS && ifd[i] != -1)
657 munmap(screen, 800*480*2);