op_test_inputs: sound test and validation version code
[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 typedef struct {
44         int x, y;
45         int code;
46         int active;
47         const char *name;
48 } key_item;
49
50 static key_item key_items[] =
51 {
52         {  66,  26, KEY_1, 0, "1" },
53         { 133,  26, KEY_2, 0, "2" },
54         { 200,  26, KEY_3, 0, "3" },
55         { 266,  26, KEY_4, 0, "4" },
56         { 333,  26, KEY_5, 0, "5" },
57         { 400,  26, KEY_6, 0, "6" },
58         { 466,  26, KEY_7, 0, "7" },
59         { 533,  26, KEY_8, 0, "8" },
60         { 600,  26, KEY_9, 0, "9" },
61         { 666,  26, KEY_0, 0, "0" },
62         { 733,  26, KEY_BACKSPACE, 0, "DEL" },
63         //
64         {  10,  55, KEY_RIGHTSHIFT,0, "L" },
65         {  10,  75, KEY_KPPLUS,    0, "L2" },
66         { 758,  55, KEY_RIGHTCTRL, 0, "R" },
67         { 758,  75, KEY_KPMINUS,   0, "R2" },
68         {  10, 220, KEY_POWER,     0, "POWER" },
69         {  10, 240, KEY_COFFEE,    0, "HOLD" },
70         //
71         { 130,  94, KEY_UP,     0, "U" },
72         {  80, 163, KEY_LEFT,   0, "L" },
73         { 180, 163, KEY_RIGHT,  0, "R" },
74         { 130, 232, KEY_DOWN,   0, "D" },
75         { 376,  94, KEY_LEFTALT,0, "ALT" },
76         { 368, 163, KEY_LEFTCTRL,0,"CTRL" },
77         { 368, 232, KEY_MENU,   0, "MENU" },
78         { 700,  94, KEY_PAGEUP, 0, "1" },
79         { 650, 163, KEY_HOME,   0, "4" },
80         { 750, 163, KEY_END,    0, "2" },
81         { 700, 232, KEY_PAGEDOWN,0, "3" },
82         //
83         {  92, 300, KEY_Q,      0, "Q" },
84         { 158, 300, KEY_W,      0, "W" },
85         { 225, 300, KEY_E,      0, "E" },
86         { 292, 300, KEY_R,      0, "R" },
87         { 358, 300, KEY_T,      0, "T" },
88         { 425, 300, KEY_Y,      0, "Y" },
89         { 492, 300, KEY_U,      0, "U" },
90         { 558, 300, KEY_I,      0, "I" },
91         { 625, 300, KEY_O,      0, "O" },
92         { 692, 300, KEY_P,      0, "P" },
93         //
94         {  30, 369, KEY_LEFTSHIFT, 0, "SHIFT" },
95         { 133, 369, KEY_A,      0, "A" },
96         { 200, 369, KEY_S,      0, "S" },
97         { 266, 369, KEY_D,      0, "D" },
98         { 333, 369, KEY_F,      0, "F" },
99         { 400, 369, KEY_G,      0, "G" },
100         { 466, 369, KEY_H,      0, "H" },
101         { 533, 369, KEY_J,      0, "J" },
102         { 600, 369, KEY_K,      0, "K" },
103         { 666, 369, KEY_L,      0, "L" },
104         { 710, 369, KEY_ENTER,  0, "ENTER" },
105         //
106         {  25, 437, KEY_COMMA,  0, "," },
107         {  92, 437, KEY_DOT,    0, "." },
108         { 158, 437, KEY_Z,      0, "Z" },
109         { 225, 437, KEY_X,      0, "X" },
110         { 292, 437, KEY_C,      0, "C" },
111         { 358, 437, KEY_V,      0, "V" },
112         { 425, 437, KEY_B,      0, "B" },
113         { 492, 437, KEY_N,      0, "N" },
114         { 558, 437, KEY_M,      0, "M" },
115         { 625, 437, KEY_SPACE,  0, "SPACE" },
116         { 758, 437, KEY_FN,     0, "Fn" },
117 };
118
119 #define KI_COUNT (sizeof(key_items) / sizeof(key_items[0]))
120
121 static int ts_old_x = 0, ts_old_y = 0;
122 static int lid_closed = 0;
123
124 static void draw_ts_cross(unsigned short *fb, unsigned short col, int x, int y)
125 {
126         int i, x1, y1;
127
128         if (y >= 0 && y < 480)
129                 for (x1 = x - 5, i = 0; i < 11; i++, x1++)
130                         if (x1 >= 0 && x1 < 800) fb[y * 800 + x1] = col;
131         
132         if (x >= 0 && x < 800)
133                 for (y1 = y - 5, i = 0; i < 11; i++, y1++)
134                         if (y1 >= 0 && y1 < 480) fb[y1 * 800 + x] = col;
135         
136         ts_old_x = x;
137         ts_old_y = y;
138 }
139
140 static void text_out16(unsigned short *fb, int x, int y, unsigned short col, const char *text)
141 {
142         int i,l;
143
144         fb = fb + x + y*800;
145
146         for (i = 0; i < strlen(text); i++)
147         {
148                 for (l=0;l<8;l++)
149                 {
150                         #define pix(fdmask,add) \
151                                 if (fontdata8x8[((text[i])*8)+l]&fdmask) \
152                                         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
153                         pix(0x80,  0);
154                         pix(0x40,  2);
155                         pix(0x20,  4);
156                         pix(0x10,  6);
157                         pix(0x08,  8);
158                         pix(0x04, 10);
159                         pix(0x02, 12);
160                         pix(0x01, 14);
161                         #undef pix
162                 }
163                 fb += 8*2;
164         }
165 }
166
167 static void text_out16_small(unsigned short *fb, int x, int y, unsigned short col, const char *text)
168 {
169         int i,l;
170
171         fb = fb + x + y*800;
172
173         for (i = 0; i < strlen(text); i++)
174         {
175                 for (l=0;l<8;l++)
176                 {
177                         #define pix(fdmask,add) \
178                                 if (fontdata8x8[((text[i])*8)+l]&fdmask) \
179                                         fb[l*800+add]=fb[l*800+800+add]=col
180                         pix(0x80,  0);
181                         pix(0x40,  1);
182                         pix(0x20,  2);
183                         pix(0x10,  3);
184                         pix(0x08,  4);
185                         pix(0x04,  5);
186                         pix(0x02,  6);
187                         pix(0x01,  7);
188                         #undef pix
189                 }
190                 fb += 8;
191         }
192 }
193
194 static void redraw_nubs(unsigned short *fb, int x1, int y1, int x2, int y2)
195 {
196         char buff[32];
197         int y;
198
199         fb += 90*800;
200
201         // clear areas
202         for (y = 0; y < 140; y++) {
203                 memset(fb + 800*y + 200, 0, (64+8)*2*2);
204                 memset(fb + 800*y + 450, 0, (64+8)*2*2);
205         }
206
207         text_out16(fb + 200, 32*2 + x1/8, 32*2 + y1/8, 0x001f, "@");
208         text_out16(fb + 450, 32*2 + x2/8, 32*2 + y2/8, 0x001f, "@");
209
210         snprintf(buff, sizeof(buff), "%2i, %2i", x1/8, y1/8);
211         text_out16_small(fb, 245, 130, 0x7bef, buff);
212         snprintf(buff, sizeof(buff), "%2i, %2i", x2/8, y2/8);
213         text_out16_small(fb, 495, 130, 0x7bef, buff);
214 }
215
216 static void redraw_keys_lid(unsigned short *fb)
217 {
218         const key_item *key;
219         int i;
220
221         for (i = 0; i < KI_COUNT; i++)
222         {
223                 key = &key_items[i];
224
225                 text_out16(fb, key->x, key->y,
226                         key->active ? 0x07e0 : 0x7bef, key->name);
227         }
228
229         text_out16(fb, 10, 260, lid_closed ? 0x07e0 : 0x7bef, "LID");
230 }
231
232 static void set_key(int code, int val)
233 {
234         key_item *key = NULL;
235         int i;
236
237         for (i = 0; i < KI_COUNT; i++)
238         {
239                 if (key_items[i].code == code)
240                 {
241                         key = &key_items[i];
242                         break;
243                 }
244         }
245
246         if (key == NULL)
247         {
248                 printf("%c unexpected key? (%i)\n", val ? '+' : '-', code);
249         }
250         else
251         {
252                 key->active = val;
253                 printf("%c %s\n", val ? '+' : '-', key->name);
254         }
255 }
256
257 /* sound test */
258 #include <sys/soundcard.h>
259 #include <pthread.h>
260
261 static int snd_test_l, snd_test_r, snd_test_quit;
262 static pthread_cond_t snd_cond = PTHREAD_COND_INITIALIZER;
263 static pthread_mutex_t snd_mutex = PTHREAD_MUTEX_INITIALIZER;
264
265 static void *sound_thread(void *arg)
266 {
267         int i, ret, randfd, dspfd;
268         int frag, bits, stereo, rate;
269         short buf[8*1024];//2*22050 / 10];
270
271         randfd = open("/dev/urandom", O_RDONLY);
272         if (randfd == -1) {
273                 perror("open(\"/dev/urandom\")");
274                 return NULL;
275         }
276
277         dspfd = open("/dev/dsp", O_WRONLY);
278         if (dspfd == -1) {
279                 perror("open(\"/dev/dsp\")");
280                 close(randfd);
281                 return NULL;
282         }
283
284         frag = (2 << 16) | 13;
285         ret = ioctl(dspfd, SNDCTL_DSP_SETFRAGMENT, &frag);
286         if (ret < 0)
287                 perror("SNDCTL_DSP_SETFRAGMENT");
288
289         stereo = 1; bits = 16; rate = 22050;
290         ret = ioctl(dspfd, SNDCTL_DSP_STEREO, &stereo);
291         if (ret == 0)
292                 ret = ioctl(dspfd, SNDCTL_DSP_SETFMT, &bits);
293         if (ret == 0)
294                 ret = ioctl(dspfd, SNDCTL_DSP_SPEED, &rate);
295         if (ret < 0)
296                 perror("failed to set audio format");
297
298         while (1) {
299                 pthread_mutex_lock(&snd_mutex);
300                 if (!snd_test_l && !snd_test_r)
301                         pthread_cond_wait(&snd_cond, &snd_mutex);
302                 pthread_mutex_unlock(&snd_mutex);
303
304                 if (snd_test_quit)
305                         break;
306
307                 ret = read(randfd, buf, sizeof(buf));
308                 if (ret == -1) {
309                         perror("urandom read");
310                         break;
311                 }
312
313                 if (!snd_test_l)
314                         for (i = 0; i < array_size(buf) / 2; i++)
315                                 buf[i * 2] = 0;
316                 if (!snd_test_r)
317                         for (i = 0; i < array_size(buf) / 2; i++)
318                                 buf[i * 2 + 1] = 0;
319
320                 ret = write(dspfd, buf, sizeof(buf));
321                 if (ret == -1) {
322                         perror("dsp write");
323                         break;
324                 }
325         }
326
327         close(randfd);
328         close(dspfd);
329
330         return NULL;
331 }
332
333 static void sound_init(void)
334 {
335         pthread_t tid;
336         int ret;
337
338         ret = pthread_create(&tid, NULL, sound_thread, NULL);
339         if (ret != 0) {
340                 fprintf(stderr, "pthread_create sound_thread: %d\n", ret);
341                 return;
342         }
343         pthread_detach(tid);
344 }
345
346 static void sound_do(int l, int r)
347 {
348         pthread_mutex_lock(&snd_mutex);
349         snd_test_l = l;
350         snd_test_r = r;
351         if (l || r || snd_test_quit)
352                 pthread_cond_signal(&snd_cond);
353         pthread_mutex_unlock(&snd_mutex);
354 }
355
356 enum {
357         DEV_PWRBTN,
358         DEV_KEYPAD,
359         DEV_BUTTONS,
360         DEV_TS,
361         DEV_LNUB,
362         DEV_RNUB,
363         DEVS_TOTAL
364 };
365
366 int main(int argc, char *argv[])
367 {
368         unsigned short *screen;
369         int fbdev, ifd[DEVS_TOTAL] = { -1, -1, -1, -1, -1, -1 };
370         int i, id, imaxfd = 0, ts_x = 0, ts_y = 0;
371         int nubx[2] = {0,0}, nuby[2] = {0,0};
372         int pressed_l = 0, pressed_r = 0;
373         struct tsdev *ts = NULL;
374
375         fbdev = open("/dev/fb0", O_RDWR);
376         if (fbdev == -1)
377         {
378                 perror("open(\"/dev/fb0\") failed");
379                 return 1;
380         }
381
382         screen = mmap(0, 800*480*2, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev, 0);
383         if (screen == MAP_FAILED)
384         {
385                 perror("mmap(fbptr) failed");
386                 return 1;
387         }
388
389         memset(screen, 0, 800*480*2);
390
391         sound_init();
392
393         for (id = 0; ; id++)
394         {
395                 char fname[64];
396                 char name[256] = { 0, };
397                 int fd;
398
399                 snprintf(fname, sizeof(fname), "/dev/input/event%i", id);
400                 fd = open(fname, O_RDONLY);
401                 if (fd == -1)
402                 {
403                         break;
404                 }
405
406                 ioctl(fd, EVIOCGNAME(sizeof(name)), name);
407
408                 if (strcasestr(name, "power") != NULL)
409                 {
410                         ifd[DEV_PWRBTN] = fd;
411                 }
412                 else if (strcasestr(name, "keypad") != NULL)
413                 {
414                         ifd[DEV_KEYPAD] = fd;
415                 }
416                 else if (strcmp(name, "gpio-keys") == 0)
417                 {
418                         ifd[DEV_BUTTONS] = fd;
419                 }
420                 else if (strcasestr(name, "touchscreen") != NULL)
421                 {
422                         close(fd);
423                         ts = ts_open(fname, 0);
424                         if (ts == NULL)
425                         {
426                                 perror("ts_open");
427                                 goto end;
428                         }
429                         if (ts_config(ts))
430                         {
431                                 perror("ts_config");
432                                 goto end;
433                         }
434                         ifd[DEV_TS] = ts_fd(ts);
435                 }
436                 else if (strcmp(name, "nub0") == 0)
437                 {
438                         ifd[DEV_LNUB] = fd;
439                 }
440                 else if (strcmp(name, "nub1") == 0)
441                 {
442                         ifd[DEV_RNUB] = fd;
443                 }
444                 else
445                 {
446                         printf("skipping \"%s\"\n", name);
447                         close(fd);
448                         continue;
449                 }
450                 if (imaxfd < fd) imaxfd = fd;
451         }
452
453         if (ifd[DEV_PWRBTN]  == -1) printf("Warning: couldn't find pwrbutton device\n");
454         if (ifd[DEV_KEYPAD]  == -1) printf("Warning: couldn't find keypad device\n");
455         if (ifd[DEV_BUTTONS] == -1) printf("Warning: couldn't find button device\n");
456         if (ifd[DEV_TS]      == -1) printf("Warning: couldn't find touchscreen device\n");
457         if (ifd[DEV_LNUB]    == -1) printf("Warning: couldn't find nub1 device\n");
458         if (ifd[DEV_RNUB]    == -1) printf("Warning: couldn't find nub2 device\n");
459
460 #ifdef VALIDATION
461         text_out16_small(screen, 220, 3, 0x7bef, "press menu/pandora to shutdown, alt/start to exit");
462 #else
463         text_out16_small(screen, 320, 3, 0x7bef, "Press L+R to exit");
464 #endif
465
466         while (!pressed_l || !pressed_r)
467         {
468                 struct input_event ev[64];
469                 int fd = -1, rd, which, ret;
470                 fd_set fdset;
471
472                 draw_ts_cross(screen, 0x0000, ts_old_x, ts_old_y);
473                 redraw_keys_lid(screen);
474                 redraw_nubs(screen, nubx[0], nuby[0], nubx[1], nuby[1]);
475                 draw_ts_cross(screen, 0xf800, ts_x, ts_y);
476
477                 FD_ZERO(&fdset);
478                 for (i = 0; i < DEVS_TOTAL; i++)
479                         if (ifd[i] != -1)
480                                 FD_SET(ifd[i], &fdset);
481
482                 ret = select(imaxfd + 1, &fdset, NULL, NULL, NULL);
483                 if (ret == -1)
484                 {
485                         perror("select");
486                         break;
487                 }
488
489                 for (i = 0; i < DEVS_TOTAL; i++)
490                         if (ifd[i] != -1 && FD_ISSET(ifd[i], &fdset))
491                                 fd = ifd[i];
492
493                 /* touch event? */
494                 if (fd == ifd[DEV_TS])
495                 {
496                         struct ts_sample samp;
497
498                         ret = ts_read(ts, &samp, 1);
499                         if (ret < 0) {
500                                 perror("ts_read");
501                                 break;
502                         }
503
504                         if (ret != 1)
505                                 continue;
506
507                         ts_x = samp.x; ts_y = samp.y;
508                         //printf("ts: %6d %6d %6d\n", samp.x, samp.y, samp.pressure);
509                         continue;
510                 }
511
512                 /* buttons or keypad */
513                 rd = read(fd, ev, sizeof(ev));
514                 if (rd < (int) sizeof(ev[0])) {
515                         perror("\nevtest: error reading");
516                         break;
517                 }
518
519                 for (i = 0; i < rd / sizeof(ev[0]); i++)
520                 {
521                         switch (ev[i].type) {
522                         case EV_SYN:
523                                 break;
524                         case EV_KEY:
525                                 set_key(ev[i].code, ev[i].value);
526 #ifndef VALIDATION
527                                 if (ev[i].code == KEY_RIGHTSHIFT)
528                                         pressed_l = !!ev[i].value;
529                                 if (ev[i].code == KEY_RIGHTCTRL)
530                                         pressed_r = !!ev[i].value;
531 #else
532                                 if (ev[i].code == KEY_LEFTALT && !!ev[i].value)
533                                         goto end;
534                                 if (ev[i].code == KEY_MENU && !!ev[i].value) {
535                                         sync();
536                                         system("poweroff -f");
537                                         goto end;
538                                 }
539 #endif
540                                 if (ev[i].code == KEY_LEFT)
541                                         sound_do(!!ev[i].value, snd_test_r);
542                                 if (ev[i].code == KEY_RIGHT)
543                                         sound_do(snd_test_l, !!ev[i].value);
544                                 break;
545                         case EV_ABS:
546                                 which = (fd == ifd[DEV_LNUB]) ? 0 : 1;
547                                 if (ev[i].code == ABS_X)
548                                         nubx[which] = ev[i].value;
549                                 else if (ev[i].code == ABS_Y)
550                                         nuby[which] = ev[i].value;
551                                 else
552                                         printf("unexpected EV_ABS code: %i\n", ev[i].code);
553                                 break;
554                         case EV_SW:
555                                 if (ev[i].code == SW_LID)
556                                         lid_closed = ev[i].value;
557                                 else
558                                         printf("unexpected EV_SW code: %i\n", ev[i].code);
559                                 break;
560                         case EV_MSC:
561                                 if (ev[i].code == MSC_SCAN)
562                                         break;
563                                 /* fallthrough */
564                         default:
565                                 printf("unexpected event: type %i, code %d\n", ev[i].type, ev[i].code);
566                                 break;
567                         }
568                 }
569         }
570
571         snd_test_quit = 1;
572         sound_do(0, 0);
573
574 end:
575         if (ts != NULL)
576                 ts_close(ts);
577         for (i = 0; i < DEVS_TOTAL; i++)
578                 if (i != DEV_TS && ifd[i] != -1)
579                         close(ifd[i]);
580         munmap(screen, 800*480*2);
581         close(fbdev);
582         return 0;
583 }
584