add op_lidstate
[pandora-misc.git] / op_test_inputs.c
1 /*
2  * Copyright (c) 2010, GraÅžvydas Ignotas
3  * All rights reserved.
4  *
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.
15  *
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.
26  */
27 #define _GNU_SOURCE
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <sys/mman.h>
35 #include <unistd.h>
36 #include <linux/input.h>
37 #include <tslib.h>
38
39 #include "font.c"
40
41 #define array_size(x) (sizeof(x) / sizeof(x[0]))
42
43 /* this sucks, but EvilDragon wants it */
44 #ifdef VALIDATION
45 #define NUB_RANGE_REQ (256-8*3)
46 #else
47 #define NUB_RANGE_REQ 256
48 #endif
49
50 typedef struct {
51         int x, y;
52         int code;
53         unsigned int active:1;
54         unsigned int tested:1;
55         const char *name;
56 } key_item;
57
58 static key_item key_items[] =
59 {
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" },
71         //
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" },
78         //
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" },
90         //
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" },
101         //
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" },
113         //
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" },
125 };
126
127 #define KI_COUNT (sizeof(key_items) / sizeof(key_items[0]))
128
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;
132
133 static void draw_ts_cross(unsigned short *fb, unsigned short col, int x, int y)
134 {
135         int i, x1, y1;
136
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;
140         
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;
144
145         if (x != ts_old_x && y != ts_old_y)
146                 ts_tested = 1;
147
148         ts_old_x = x;
149         ts_old_y = y;
150 }
151
152 static void text_out16(unsigned short *fb, int x, int y, unsigned short col, const char *text)
153 {
154         int i,l;
155
156         fb = fb + x + y*800;
157
158         for (i = 0; i < strlen(text); i++)
159         {
160                 for (l=0;l<8;l++)
161                 {
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
165                         pix(0x80,  0);
166                         pix(0x40,  2);
167                         pix(0x20,  4);
168                         pix(0x10,  6);
169                         pix(0x08,  8);
170                         pix(0x04, 10);
171                         pix(0x02, 12);
172                         pix(0x01, 14);
173                         #undef pix
174                 }
175                 fb += 8*2;
176         }
177 }
178
179 static void text_out16_small(unsigned short *fb, int x, int y, unsigned short col, const char *text)
180 {
181         int i,l;
182
183         fb = fb + x + y*800;
184
185         for (i = 0; i < strlen(text); i++)
186         {
187                 for (l=0;l<8;l++)
188                 {
189                         #define pix(fdmask,add) \
190                                 if (fontdata8x8[((text[i])*8)+l]&fdmask) \
191                                         fb[l*800+add]=fb[l*800+800+add]=col
192                         pix(0x80,  0);
193                         pix(0x40,  1);
194                         pix(0x20,  2);
195                         pix(0x10,  3);
196                         pix(0x08,  4);
197                         pix(0x04,  5);
198                         pix(0x02,  6);
199                         pix(0x01,  7);
200                         #undef pix
201                 }
202                 fb += 8;
203         }
204 }
205
206 static void redraw_nubs(unsigned short *fb, int x1, int y1, int x2, int y2)
207 {
208         char buff[32];
209         int fill = 0, y;
210
211         fb += 90*800;
212
213         if (nub_range_hit == 0xff && all_btns_tested && lid_tested && ts_tested)
214                 fill = 3;
215
216         // clear areas
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);
220         }
221
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, "@");
224
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;
233
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);
238
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);
243 }
244
245 static void redraw_keys_lid(unsigned short *fb)
246 {
247         const key_item *key;
248         int i;
249
250         for (i = 0; i < KI_COUNT; i++)
251         {
252                 key = &key_items[i];
253
254                 text_out16(fb, key->x, key->y,
255                         key->active ? 0x07e0 : (key->tested ? 0xce6f : 0x7bef),
256                         key->name);
257         }
258
259         text_out16(fb, 10, 260, lid_closed ? 0x07e0 : (lid_tested ? 0xce6f : 0x7bef), "LID");
260 }
261
262 static void set_key(int code, int val)
263 {
264         key_item *key = NULL;
265         int i;
266
267         for (i = 0; i < KI_COUNT; i++)
268         {
269                 if (key_items[i].code == code)
270                 {
271                         key = &key_items[i];
272                         break;
273                 }
274         }
275
276         if (key == NULL)
277         {
278                 printf("%c unexpected key? (%i)\n", val ? '+' : '-', code);
279         }
280         else
281         {
282                 key->active = !!val;
283                 key->tested |= !!val;
284                 printf("%c %s\n", val ? '+' : '-', key->name);
285         }
286
287         if (all_btns_tested)
288                 return;
289
290         for (i = 0; i < KI_COUNT; i++)
291         {
292                 if (key_items[i].code == KEY_MENU)
293                         continue;
294                 if (key_items[i].code == KEY_KPPLUS || key_items[i].code == KEY_KPMINUS)
295                         continue;
296                 if (!key_items[i].tested)
297                         break;
298         }
299
300         if (i == KI_COUNT)
301                 all_btns_tested = 1;
302 }
303
304 /* sound test */
305 #include <sys/soundcard.h>
306 #include <pthread.h>
307
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;
311
312 static void *sound_thread(void *arg)
313 {
314         int i, ret, randfd, dspfd;
315         int frag, bits, stereo, rate;
316         short buf[8*1024];//2*22050 / 10];
317
318         randfd = open("/dev/urandom", O_RDONLY);
319         if (randfd == -1) {
320                 perror("open(\"/dev/urandom\")");
321                 return NULL;
322         }
323
324         dspfd = open("/dev/dsp", O_WRONLY);
325         if (dspfd == -1) {
326                 perror("open(\"/dev/dsp\")");
327                 close(randfd);
328                 return NULL;
329         }
330
331         frag = (2 << 16) | 13;
332         ret = ioctl(dspfd, SNDCTL_DSP_SETFRAGMENT, &frag);
333         if (ret < 0)
334                 perror("SNDCTL_DSP_SETFRAGMENT");
335
336         stereo = 1; bits = 16; rate = 22050;
337         ret = ioctl(dspfd, SNDCTL_DSP_STEREO, &stereo);
338         if (ret == 0)
339                 ret = ioctl(dspfd, SNDCTL_DSP_SETFMT, &bits);
340         if (ret == 0)
341                 ret = ioctl(dspfd, SNDCTL_DSP_SPEED, &rate);
342         if (ret < 0)
343                 perror("failed to set audio format");
344
345         while (1) {
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);
350
351                 if (snd_test_quit)
352                         break;
353
354                 ret = read(randfd, buf, sizeof(buf));
355                 if (ret == -1) {
356                         perror("urandom read");
357                         break;
358                 }
359
360                 if (!snd_test_l)
361                         for (i = 0; i < array_size(buf) / 2; i++)
362                                 buf[i * 2] = 0;
363                 if (!snd_test_r)
364                         for (i = 0; i < array_size(buf) / 2; i++)
365                                 buf[i * 2 + 1] = 0;
366
367                 ret = write(dspfd, buf, sizeof(buf));
368                 if (ret == -1) {
369                         perror("dsp write");
370                         break;
371                 }
372         }
373
374         close(randfd);
375         close(dspfd);
376
377         return NULL;
378 }
379
380 static void sound_init(void)
381 {
382         pthread_t tid;
383         int ret;
384
385         ret = pthread_create(&tid, NULL, sound_thread, NULL);
386         if (ret != 0) {
387                 fprintf(stderr, "pthread_create sound_thread: %d\n", ret);
388                 return;
389         }
390         pthread_detach(tid);
391 }
392
393 static void sound_do(int l, int r)
394 {
395         pthread_mutex_lock(&snd_mutex);
396         snd_test_l = l;
397         snd_test_r = r;
398         if (l || r || snd_test_quit)
399                 pthread_cond_signal(&snd_cond);
400         pthread_mutex_unlock(&snd_mutex);
401 }
402
403 enum {
404         DEV_PWRBTN,
405         DEV_KEYPAD,
406         DEV_BUTTONS,
407         DEV_TS,
408         DEV_LNUB,
409         DEV_RNUB,
410         DEVS_TOTAL
411 };
412
413 int main(int argc, char *argv[])
414 {
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;
421         int retval = 0;
422
423         fbdev = open("/dev/fb0", O_RDWR);
424         if (fbdev == -1)
425         {
426                 perror("open(\"/dev/fb0\") failed");
427                 return 1;
428         }
429
430         screen = mmap(0, 800*480*2, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev, 0);
431         if (screen == MAP_FAILED)
432         {
433                 perror("mmap(fbptr) failed");
434                 return 1;
435         }
436
437         memset(screen, 0, 800*480*2);
438
439         sound_init();
440
441         for (id = 0; ; id++)
442         {
443                 char fname[64];
444                 char name[256] = { 0, };
445                 int fd;
446
447                 snprintf(fname, sizeof(fname), "/dev/input/event%i", id);
448                 fd = open(fname, O_RDONLY);
449                 if (fd == -1)
450                 {
451                         break;
452                 }
453
454                 ioctl(fd, EVIOCGNAME(sizeof(name)), name);
455
456                 if (strcasestr(name, "power") != NULL || strcasestr(name, "pwrbutton") != NULL)
457                 {
458                         ifd[DEV_PWRBTN] = fd;
459                 }
460                 else if (strcasestr(name, "keypad") != NULL)
461                 {
462                         ifd[DEV_KEYPAD] = fd;
463                 }
464                 else if (strcmp(name, "gpio-keys") == 0)
465                 {
466                         ifd[DEV_BUTTONS] = fd;
467                 }
468                 else if (strcasestr(name, "touchscreen") != NULL)
469                 {
470                         close(fd);
471                         ts = ts_open(fname, 0);
472                         if (ts == NULL)
473                         {
474                                 perror("ts_open");
475                                 goto end;
476                         }
477                         if (ts_config(ts))
478                         {
479                                 perror("ts_config");
480                                 goto end;
481                         }
482                         ifd[DEV_TS] = ts_fd(ts);
483                 }
484                 else if (strcmp(name, "nub0") == 0)
485                 {
486                         ifd[DEV_LNUB] = fd;
487                 }
488                 else if (strcmp(name, "nub1") == 0)
489                 {
490                         ifd[DEV_RNUB] = fd;
491                 }
492                 else
493                 {
494                         printf("skipping \"%s\"\n", name);
495                         close(fd);
496                         continue;
497                 }
498                 if (imaxfd < fd) imaxfd = fd;
499         }
500
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 */
509                 retval = -1;
510                 goto end;
511         }
512
513 #ifdef VALIDATION
514         int early_leave_attempt = 0;
515         text_out16_small(screen, 220, 3, 0x7bef,
516                          "press menu/pandora to exit");
517 #else
518         text_out16_small(screen, 320, 3, 0x7bef, "Press L+R to exit");
519 #endif
520
521 #ifdef VALIDATION
522         while (1)
523 #else
524         while (!pressed_l || !pressed_r)
525 #endif
526         {
527                 struct input_event ev[64];
528                 int fd = -1, rd, which, ret;
529                 fd_set fdset;
530
531 #ifdef VALIDATION
532                 if (early_leave_attempt > 1) {
533                         char buff[128];
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");
541                         else
542                                 text_out16_small(screen, 4, 3, 0xf800, buff);
543                 }
544 #endif
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);
549
550                 FD_ZERO(&fdset);
551                 for (i = 0; i < DEVS_TOTAL; i++)
552                         if (ifd[i] != -1)
553                                 FD_SET(ifd[i], &fdset);
554
555                 ret = select(imaxfd + 1, &fdset, NULL, NULL, NULL);
556                 if (ret == -1)
557                 {
558                         perror("select");
559                         break;
560                 }
561
562                 for (i = 0; i < DEVS_TOTAL; i++)
563                         if (ifd[i] != -1 && FD_ISSET(ifd[i], &fdset))
564                                 fd = ifd[i];
565
566                 /* touch event? */
567                 if (fd == ifd[DEV_TS])
568                 {
569                         struct ts_sample samp;
570
571                         ret = ts_read(ts, &samp, 1);
572                         if (ret < 0) {
573                                 perror("ts_read");
574                                 break;
575                         }
576
577                         if (ret != 1)
578                                 continue;
579
580                         ts_x = samp.x; ts_y = samp.y;
581                         //printf("ts: %6d %6d %6d\n", samp.x, samp.y, samp.pressure);
582                         continue;
583                 }
584
585                 /* buttons or keypad */
586                 rd = read(fd, ev, sizeof(ev));
587                 if (rd < (int) sizeof(ev[0])) {
588                         perror("\nevtest: error reading");
589                         break;
590                 }
591
592                 for (i = 0; i < rd / sizeof(ev[0]); i++)
593                 {
594                         switch (ev[i].type) {
595                         case EV_SYN:
596                                 break;
597                         case EV_KEY:
598                                 set_key(ev[i].code, ev[i].value);
599
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;
604 #ifdef VALIDATION
605                                 if (ev[i].code == KEY_MENU && !!ev[i].value) {
606                                         if (nub_range_hit == 0xff && all_btns_tested && lid_tested && ts_tested)
607                                                 goto end;
608                                         if (pressed_l && pressed_r) {
609                                                 retval = 1;
610                                                 goto end;
611                                         }
612                                         early_leave_attempt++;
613                                 }
614 #endif
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);
619                                 break;
620                         case EV_ABS:
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;
626                                 else
627                                         printf("unexpected EV_ABS code: %i\n", ev[i].code);
628                                 break;
629                         case EV_SW:
630                                 if (ev[i].code == SW_LID) {
631                                         lid_closed = ev[i].value;
632                                         lid_tested |= ev[i].value;
633                                 }
634                                 else
635                                         printf("unexpected EV_SW code: %i\n", ev[i].code);
636                                 break;
637                         case EV_MSC:
638                                 if (ev[i].code == MSC_SCAN)
639                                         break;
640                                 /* fallthrough */
641                         default:
642                                 printf("unexpected event: type %i, code %d\n", ev[i].type, ev[i].code);
643                                 break;
644                         }
645                 }
646         }
647
648         snd_test_quit = 1;
649         sound_do(0, 0);
650
651 end:
652         if (ts != NULL)
653                 ts_close(ts);
654         for (i = 0; i < DEVS_TOTAL; i++)
655                 if (i != DEV_TS && ifd[i] != -1)
656                         close(ifd[i]);
657         munmap(screen, 800*480*2);
658         close(fbdev);
659         return retval;
660 }
661