1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36#include <common.h>
37
38#include <version.h>
39#include <linux/types.h>
40#include <stdio_dev.h>
41
42#include <sed156x.h>
43
44
45
46#define ROWS 24
47#define COLS 80
48
49#define REFRESH_HZ (CONFIG_SYS_HZ/50)
50#define BLINK_HZ (CONFIG_SYS_HZ/2)
51
52
53
54#define DISPLAY_BACKLIT_PORT ((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdat
55#define DISPLAY_BACKLIT_MASK 0x0010
56
57
58
59#define KP_STABLE_HZ (CONFIG_SYS_HZ/100)
60#define KP_REPEAT_DELAY_HZ (CONFIG_SYS_HZ/4)
61#define KP_REPEAT_HZ (CONFIG_SYS_HZ/20)
62#define KP_FORCE_DELAY_HZ (CONFIG_SYS_HZ/2)
63#define KP_IDLE_DELAY_HZ (CONFIG_SYS_HZ/2)
64
65#if CONFIG_NETPHONE_VERSION == 1
66#define KP_SPI_RXD_PORT (((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdat)
67#define KP_SPI_RXD_MASK 0x0008
68
69#define KP_SPI_TXD_PORT (((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdat)
70#define KP_SPI_TXD_MASK 0x0004
71
72#define KP_SPI_CLK_PORT (((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport.iop_pcdat)
73#define KP_SPI_CLK_MASK 0x0001
74#elif CONFIG_NETPHONE_VERSION == 2
75#define KP_SPI_RXD_PORT (((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdat)
76#define KP_SPI_RXD_MASK 0x00000008
77
78#define KP_SPI_TXD_PORT (((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdat)
79#define KP_SPI_TXD_MASK 0x00000004
80
81#define KP_SPI_CLK_PORT (((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pbdat)
82#define KP_SPI_CLK_MASK 0x00000002
83#endif
84
85#define KP_CS_PORT (((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pedat)
86#define KP_CS_MASK 0x00000010
87
88#define KP_SPI_RXD() (KP_SPI_RXD_PORT & KP_SPI_RXD_MASK)
89
90#define KP_SPI_TXD(x) \
91 do { \
92 if (x) \
93 KP_SPI_TXD_PORT |= KP_SPI_TXD_MASK; \
94 else \
95 KP_SPI_TXD_PORT &= ~KP_SPI_TXD_MASK; \
96 } while(0)
97
98#define KP_SPI_CLK(x) \
99 do { \
100 if (x) \
101 KP_SPI_CLK_PORT |= KP_SPI_CLK_MASK; \
102 else \
103 KP_SPI_CLK_PORT &= ~KP_SPI_CLK_MASK; \
104 } while(0)
105
106#define KP_SPI_CLK_TOGGLE() (KP_SPI_CLK_PORT ^= KP_SPI_CLK_MASK)
107
108#define KP_SPI_BIT_DELAY()
109
110#define KP_CS(x) \
111 do { \
112 if (x) \
113 KP_CS_PORT |= KP_CS_MASK; \
114 else \
115 KP_CS_PORT &= ~KP_CS_MASK; \
116 } while(0)
117
118#define KP_ROWS 7
119#define KP_COLS 4
120
121#define KP_ROWS_MASK ((1 << KP_ROWS) - 1)
122#define KP_COLS_MASK ((1 << KP_COLS) - 1)
123
124#define SCAN 0
125#define SCAN_FILTER 1
126#define SCAN_COL 2
127#define SCAN_COL_FILTER 3
128#define PRESSED 4
129
130#define KP_F1 0
131#define KP_F2 1
132#define KP_F3 2
133#define KP_F4 3
134#define KP_F5 4
135#define KP_F6 5
136#define KP_F7 6
137#define KP_F8 7
138#define KP_F9 8
139#define KP_F10 9
140#define KP_F11 10
141#define KP_F12 11
142#define KP_F13 12
143#define KP_F14 13
144#define KP_F15 14
145#define KP_F16 15
146
147#define KP_RELEASE -1
148#define KP_FORCE -2
149#define KP_IDLE -3
150
151#define KP_1 '1'
152#define KP_2 '2'
153#define KP_3 '3'
154#define KP_4 '4'
155#define KP_5 '5'
156#define KP_6 '6'
157#define KP_7 '7'
158#define KP_8 '8'
159#define KP_9 '9'
160#define KP_0 '0'
161#define KP_STAR '*'
162#define KP_HASH '#'
163
164
165
166static int curs_disabled;
167static int curs_col, curs_row;
168static int disp_col, disp_row;
169
170static int width, height;
171
172
173static char vty_buf[ROWS * COLS];
174static char last_visible_buf[ROWS * COLS];
175static char *last_visible_curs_ptr;
176static int last_visible_curs_rev;
177static int blinked_state;
178static int last_input_mode;
179static int refresh_time;
180static int blink_time;
181static char last_fast_punct;
182
183
184
185#define IM_SMALL 0
186#define IM_CAPITAL 1
187#define IM_NUMBER 2
188
189static int input_mode;
190static char fast_punct;
191static int tab_indicator;
192static const char *fast_punct_list = ",.:;*";
193
194static const char *input_mode_txt[] = { "abc", "ABC", "123" };
195
196static const char *punct = ".,!;?'\"-()@/:_+&%*=<>$[]{}\\~^#|";
197static const char *whspace = " 0\n";
198
199static const char *digits_sel[2][8] = {
200 {
201 "abc2",
202 "def3",
203 "ghi4",
204 "jkl5",
205 "mno6",
206 "pqrs7",
207 "tuv8",
208 "wxyz9",
209 }, {
210 "ABC2",
211 "DEF3",
212 "GHI4",
213 "JKL5",
214 "MNO6",
215 "PQRS7",
216 "TUV8",
217 "WXYZ9",
218 }
219};
220
221
222
223static void update(void);
224static void ensure_visible(int col, int row, int dx, int dy);
225
226static void console_init(void)
227{
228 curs_disabled = 0;
229 curs_col = 0;
230 curs_row = 0;
231
232 disp_col = 0;
233 disp_row = 0;
234
235 input_mode = IM_SMALL;
236 fast_punct = ',';
237 last_fast_punct = '\0';
238 refresh_time = REFRESH_HZ;
239 blink_time = BLINK_HZ;
240
241 memset(vty_buf, ' ', sizeof(vty_buf));
242
243 memset(last_visible_buf, ' ', sizeof(last_visible_buf));
244 last_visible_curs_ptr = NULL;
245 last_input_mode = -1;
246 last_visible_curs_rev = 0;
247
248 blinked_state = 0;
249
250 sed156x_init();
251 width = sed156x_text_width;
252 height = sed156x_text_height - 1;
253
254 tab_indicator = 0;
255}
256
257
258
259void phone_putc(const char c);
260
261
262
263static int queued_char = -1;
264static int enabled = 0;
265
266
267
268
269int phone_start(void)
270{
271 console_init();
272
273 update();
274 sed156x_sync();
275
276 enabled = 1;
277 queued_char = 'U' - '@';
278
279
280 DISPLAY_BACKLIT_PORT &= ~DISPLAY_BACKLIT_MASK;
281
282 return 0;
283}
284
285int phone_stop(void)
286{
287 enabled = 0;
288
289 sed156x_clear();
290 sed156x_sync();
291
292
293 DISPLAY_BACKLIT_PORT |= DISPLAY_BACKLIT_MASK;
294
295 return 0;
296}
297
298void phone_puts(const char *s)
299{
300 int count = strlen(s);
301
302 while (count--)
303 phone_putc(*s++);
304}
305
306int phone_tstc(void)
307{
308 return queued_char >= 0 ? 1 : 0;
309}
310
311int phone_getc(void)
312{
313 int r;
314
315 if (queued_char < 0)
316 return -1;
317
318 r = queued_char;
319 queued_char = -1;
320
321 return r;
322}
323
324
325
326int drv_phone_init(void)
327{
328 struct stdio_dev console_dev;
329
330 console_init();
331
332 memset(&console_dev, 0, sizeof(console_dev));
333 strcpy(console_dev.name, "phone");
334 console_dev.ext = DEV_EXT_VIDEO;
335 console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
336 console_dev.start = phone_start;
337 console_dev.stop = phone_stop;
338 console_dev.putc = phone_putc;
339 console_dev.puts = phone_puts;
340 console_dev.tstc = phone_tstc;
341 console_dev.getc = phone_getc;
342
343 if (stdio_register(&console_dev) == 0)
344 return 1;
345
346 return 0;
347}
348
349static int use_me;
350
351int drv_phone_use_me(void)
352{
353 return use_me;
354}
355
356static void kp_do_poll(void);
357
358void phone_console_do_poll(void)
359{
360 int i, x, y;
361
362 kp_do_poll();
363
364 if (enabled) {
365
366 blink_time -= PHONE_CONSOLE_POLL_HZ;
367 if (blink_time <= 0) {
368 blink_time += BLINK_HZ;
369 if (last_visible_curs_ptr) {
370 i = last_visible_curs_ptr - last_visible_buf;
371 x = i % width; y = i / width;
372 sed156x_reverse_at(x, y, 1);
373 last_visible_curs_rev ^= 1;
374 }
375 }
376
377
378 refresh_time -= PHONE_CONSOLE_POLL_HZ;
379 if (refresh_time <= 0) {
380 refresh_time += REFRESH_HZ;
381 sed156x_sync();
382 }
383 }
384
385}
386
387static int last_scancode = -1;
388static int forced_scancode = 0;
389static int input_state = -1;
390static int input_scancode = -1;
391static int input_selected_char = -1;
392static char input_covered_char;
393
394static void putchar_at_cursor(char c)
395{
396 vty_buf[curs_row * COLS + curs_col] = c;
397 ensure_visible(curs_col, curs_row, 1, 1);
398}
399
400static char getchar_at_cursor(void)
401{
402 return vty_buf[curs_row * COLS + curs_col];
403}
404
405static void queue_input_char(char c)
406{
407 if (c <= 0)
408 return;
409
410 queued_char = c;
411}
412
413static void terminate_input(void)
414{
415 if (input_state < 0)
416 return;
417
418 if (input_selected_char >= 0)
419 queue_input_char(input_selected_char);
420
421 input_state = -1;
422 input_selected_char = -1;
423 putchar_at_cursor(input_covered_char);
424
425 curs_disabled = 0;
426 blink_time = BLINK_HZ;
427 update();
428}
429
430static void handle_enabled_scancode(int scancode)
431{
432 char c;
433 int new_disp_col, new_disp_row;
434 const char *sel;
435
436
437 switch (scancode) {
438
439
440 case KP_RELEASE:
441 forced_scancode = 0;
442 break;
443
444
445 case KP_FORCE:
446
447 switch (last_scancode) {
448 case '#':
449 if (input_mode == IM_NUMBER) {
450 input_mode = IM_CAPITAL;
451
452 queue_input_char('\b');
453 } else {
454 input_mode = IM_NUMBER;
455 fast_punct = '*';
456 }
457 update();
458 break;
459
460 case '0': case '1':
461 case '2': case '3': case '4': case '5':
462 case '6': case '7': case '8': case '9':
463
464 if (input_state < 0)
465 break;
466
467 input_selected_char = last_scancode;
468 putchar_at_cursor((char)input_selected_char);
469 terminate_input();
470
471 break;
472
473 default:
474 break;
475 }
476
477 break;
478
479
480 case KP_IDLE:
481 input_scancode = -1;
482 if (input_state < 0)
483 break;
484 terminate_input();
485 break;
486
487
488 case '#':
489 if (last_scancode == '#')
490 break;
491
492 if (input_mode == IM_NUMBER) {
493 input_scancode = scancode;
494 input_state = 0;
495 input_selected_char = scancode;
496 input_covered_char = getchar_at_cursor();
497 putchar_at_cursor((char)input_selected_char);
498 terminate_input();
499 break;
500 }
501
502 if (input_mode == IM_SMALL)
503 input_mode = IM_CAPITAL;
504 else
505 input_mode = IM_SMALL;
506
507 update();
508 break;
509
510 case '*':
511
512 if (last_scancode == scancode)
513 break;
514
515 if (input_state >= 0)
516 terminate_input();
517
518 input_scancode = fast_punct;
519 input_state = 0;
520 input_selected_char = input_scancode;
521 input_covered_char = getchar_at_cursor();
522 putchar_at_cursor((char)input_selected_char);
523 terminate_input();
524
525 break;
526
527 case '0': case '1':
528 case '2': case '3': case '4': case '5':
529 case '6': case '7': case '8': case '9':
530
531
532 if (last_scancode == scancode)
533 break;
534
535 if (input_mode == IM_NUMBER) {
536 input_scancode = scancode;
537 input_state = 0;
538 input_selected_char = scancode;
539 input_covered_char = getchar_at_cursor();
540 putchar_at_cursor((char)input_selected_char);
541 terminate_input();
542 break;
543 }
544
545 if (input_state >= 0 && input_scancode != scancode)
546 terminate_input();
547
548 if (input_state < 0) {
549 curs_disabled = 1;
550 input_scancode = scancode;
551 input_state = 0;
552 input_covered_char = getchar_at_cursor();
553 } else
554 input_state++;
555
556 if (scancode == '0')
557 sel = whspace;
558 else if (scancode == '1')
559 sel = punct;
560 else
561 sel = digits_sel[input_mode][scancode - '2'];
562 c = *(sel + input_state);
563 if (c == '\0') {
564 input_state = 0;
565 c = *sel;
566 }
567
568 input_selected_char = (int)c;
569 putchar_at_cursor((char)input_selected_char);
570 update();
571
572 break;
573
574
575 case KP_F3: case KP_F8: case KP_F7: case KP_F9:
576
577 new_disp_col = disp_col;
578 new_disp_row = disp_row;
579
580 switch (scancode) {
581
582 case KP_F3:
583 if (new_disp_row <= 0)
584 break;
585 new_disp_row--;
586 break;
587
588
589 case KP_F8:
590 if (new_disp_row >= ROWS - height)
591 break;
592 new_disp_row++;
593 break;
594
595
596 case KP_F7:
597 if (new_disp_col <= 0)
598 break;
599 new_disp_col--;
600 break;
601
602
603 case KP_F9:
604 if (new_disp_col >= COLS - width)
605 break;
606 new_disp_col++;
607 break;
608 }
609
610
611 if (disp_col == new_disp_col && disp_row == new_disp_row)
612 break;
613
614 disp_col = new_disp_col;
615 disp_row = new_disp_row;
616 update();
617
618 break;
619
620 case KP_F6:
621
622 if (input_state >= 0) {
623 input_selected_char = -1;
624 terminate_input();
625 break;
626 }
627 queue_input_char('\b');
628 break;
629
630 case KP_F10:
631
632 if (input_state >= 0)
633 terminate_input();
634 queue_input_char('\r');
635 break;
636
637 case KP_F11:
638 if (input_state >= 0)
639 terminate_input();
640 queue_input_char('C' - 'Q');
641 break;
642
643 case KP_F5:
644 if (input_state >= 0)
645 terminate_input();
646 queue_input_char('U' - 'Q');
647 break;
648
649
650 case KP_F1:
651
652 if (input_state >= 0)
653 terminate_input();
654 queue_input_char('\t');
655 break;
656
657 case KP_F2:
658 sel = strchr(fast_punct_list, fast_punct);
659 if (sel == NULL)
660 sel = &fast_punct_list[0];
661 sel++;
662 if (*sel == '\0')
663 sel = &fast_punct_list[0];
664 fast_punct = *sel;
665 update();
666 break;
667
668
669 }
670
671 if (scancode != KP_FORCE && scancode != KP_IDLE)
672 last_scancode = scancode;
673}
674
675static void scancode_action(int scancode)
676{
677#if 0
678 if (scancode == KP_RELEASE)
679 printf(" RELEASE\n");
680 else if (scancode == KP_FORCE)
681 printf(" FORCE\n");
682 else if (scancode == KP_IDLE)
683 printf(" IDLE\n");
684 else if (scancode < 32)
685 printf(" F%d", scancode + 1);
686 else
687 printf(" %c", (char)scancode);
688 printf("\n");
689#endif
690
691 if (enabled) {
692 handle_enabled_scancode(scancode);
693 return;
694 }
695
696 if (scancode == KP_FORCE && last_scancode == '*')
697 use_me = 1;
698
699 last_scancode = scancode;
700}
701
702
703
704
705static void update(void)
706{
707 int i;
708 char *s, *e, *t, *r, *b, *cp;
709
710 if (input_mode != last_input_mode)
711 sed156x_output_at(sed156x_text_width - 3, sed156x_text_height - 1, input_mode_txt[input_mode], 3);
712
713 if (tab_indicator == 0) {
714 sed156x_output_at(0, sed156x_text_height - 1, "\\t", 2);
715 tab_indicator = 1;
716 }
717
718 if (fast_punct != last_fast_punct)
719 sed156x_output_at(4, sed156x_text_height - 1, &fast_punct, 1);
720
721 if (curs_disabled ||
722 curs_col < disp_col || curs_col >= (disp_col + width) ||
723 curs_row < disp_row || curs_row >= (disp_row + height)) {
724 cp = NULL;
725 } else
726 cp = last_visible_buf + (curs_row - disp_row) * width + (curs_col - disp_col);
727
728
729
730
731
732 if (last_visible_curs_ptr && last_visible_curs_rev == 0) {
733 i = last_visible_curs_ptr - last_visible_buf;
734 sed156x_reverse_at(i % width, i / width, 1);
735 }
736
737 b = vty_buf + disp_row * COLS + disp_col;
738 t = last_visible_buf;
739 for (i = 0; i < height; i++) {
740 s = b;
741 e = b + width;
742
743 do {
744 while (s < e && *s == *t) {
745 s++;
746 t++;
747 }
748 if (s == e)
749 break;
750
751
752 r = s;
753 while (s < e && *s != *t)
754 *t++ = *s++;
755
756
757 sed156x_output_at(r - b, i, r, s - r);
758
759 } while (s < e);
760
761 b += COLS;
762 }
763
764
765 if (cp) {
766 last_visible_curs_ptr = cp;
767 i = last_visible_curs_ptr - last_visible_buf;
768 sed156x_reverse_at(i % width, i / width, 1);
769 last_visible_curs_rev = 0;
770 } else {
771 last_visible_curs_ptr = NULL;
772 }
773
774 last_input_mode = input_mode;
775 last_fast_punct = fast_punct;
776}
777
778
779static void ensure_visible(int col, int row, int dx, int dy)
780{
781 int x1, y1, x2, y2, a1, b1, a2, b2;
782
783
784 if (col < 0) {
785 dx -= col;
786 col = 0;
787 if (dx <= 0)
788 dx = 1;
789 }
790
791 if (row < 0) {
792 dy -= row;
793 row = 0;
794 if (dy <= 0)
795 dy = 1;
796 }
797
798 if (col + dx > COLS)
799 dx = COLS - col;
800
801 if (row + dy > ROWS)
802 dy = ROWS - row;
803
804
805
806 x1 = disp_col; y1 = disp_row;
807 x2 = x1 + width; y2 = y1 + height;
808 a1 = col; b1 = row;
809 a2 = a1 + dx; b2 = b1 + dy;
810
811
812
813 if (a2 > x2) {
814
815 x2 = a2;
816 x1 = x2 - width;
817 if (x1 < 0) {
818 x1 = 0;
819 x2 = width;
820 }
821 } else if (a1 < x1) {
822
823 x1 = a1;
824 x2 = x1 + width;
825 if (x2 > COLS) {
826 x2 = COLS;
827 x1 = x2 - width;
828 }
829 }
830
831 if (b2 > y2) {
832
833 y2 = b2;
834 y1 = y2 - height;
835 if (y1 < 0) {
836 y1 = 0;
837 y2 = height;
838 }
839 } else if (b1 < y1) {
840
841 y1 = b1;
842 y2 = y1 + width;
843 if (y2 > ROWS) {
844 y2 = ROWS;
845 y1 = y2 - height;
846 }
847 }
848
849
850
851
852 if (disp_col == x1 && disp_row == y1)
853 return;
854
855 disp_col = x1;
856 disp_row = y1;
857}
858
859
860
861static void newline(void)
862{
863 curs_col = 0;
864 if (curs_row + 1 < ROWS)
865 curs_row++;
866 else {
867 memmove(vty_buf, vty_buf + COLS, COLS * (ROWS - 1));
868 memset(vty_buf + (ROWS - 1) * COLS, ' ', COLS);
869 }
870}
871
872void phone_putc(const char c)
873{
874 int i;
875
876 if (input_mode != -1) {
877 input_selected_char = -1;
878 terminate_input();
879 }
880
881 curs_disabled = 1;
882 update();
883
884 blink_time = BLINK_HZ;
885
886 switch (c) {
887 case '\a':
888 case '\r':
889 break;
890
891 case '\n':
892 newline();
893 ensure_visible(curs_col, curs_row, 1, 1);
894 break;
895
896 case 9:
897
898 i = curs_col;
899 i |= 0x0008;
900 i &= ~0x0007;
901
902 if (i < COLS)
903 curs_col = i;
904 else
905 newline();
906
907 ensure_visible(curs_col, curs_row, 1, 1);
908 break;
909
910 case 8:
911 if (curs_col <= 0)
912 break;
913 curs_col--;
914
915
916 if (curs_col > 4)
917 ensure_visible(curs_col - 4, curs_row, 4, 1);
918 else
919 ensure_visible(curs_col, curs_row, 1, 1);
920
921 break;
922
923 default:
924 putchar_at_cursor(c);
925
926
927
928
929 if (curs_col + 1 < COLS)
930 curs_col++;
931 else
932 newline();
933
934 ensure_visible(curs_col, curs_row, 1, 1);
935
936 break;
937 }
938
939 curs_disabled = 0;
940 blink_time = BLINK_HZ;
941 update();
942}
943
944
945
946static inline unsigned int kp_transfer(unsigned int val)
947{
948 unsigned int rx;
949 int b;
950
951 rx = 0; b = 8;
952 while (--b >= 0) {
953 KP_SPI_TXD(val & 0x80);
954 val <<= 1;
955 KP_SPI_CLK_TOGGLE();
956 KP_SPI_BIT_DELAY();
957 rx <<= 1;
958 if (KP_SPI_RXD())
959 rx |= 1;
960 KP_SPI_CLK_TOGGLE();
961 KP_SPI_BIT_DELAY();
962 }
963
964 return rx;
965}
966
967unsigned int kp_data_transfer(unsigned int val)
968{
969 KP_SPI_CLK(1);
970 KP_CS(0);
971 val = kp_transfer(val);
972 KP_CS(1);
973
974 return val;
975}
976
977unsigned int kp_get_col_mask(unsigned int row_mask)
978{
979 unsigned int val, col_mask;
980
981 val = 0x80 | (row_mask & 0x7F);
982 (void)kp_data_transfer(val);
983#if CONFIG_NETPHONE_VERSION == 1
984 col_mask = kp_data_transfer(val) & 0x0F;
985#elif CONFIG_NETPHONE_VERSION == 2
986 col_mask = ((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm.cp_pedat & 0x0f;
987
988 col_mask = ((col_mask & 0x08) >> 3) |
989 ((col_mask & 0x04) << 1) |
990 (col_mask & 0x02) |
991 ((col_mask & 0x01) << 2);
992
993#endif
994
995
996 return col_mask;
997}
998
999
1000
1001static const int kp_scancodes[KP_ROWS * KP_COLS] = {
1002 KP_F1, KP_F3, KP_F4, KP_F2,
1003 KP_F6, KP_F8, KP_F9, KP_F7,
1004 KP_1, KP_3, KP_F11, KP_2,
1005 KP_4, KP_6, KP_F12, KP_5,
1006 KP_7, KP_9, KP_F13, KP_8,
1007 KP_STAR, KP_HASH, KP_F14, KP_0,
1008 KP_F5, KP_F15, KP_F16, KP_F10,
1009};
1010
1011static const int kp_repeats[KP_ROWS * KP_COLS] = {
1012 0, 1, 0, 0,
1013 0, 1, 1, 1,
1014 1, 1, 0, 1,
1015 1, 1, 0, 1,
1016 1, 1, 0, 1,
1017 1, 1, 0, 1,
1018 0, 0, 0, 1,
1019};
1020
1021static int kp_state = SCAN;
1022static int kp_last_col_mask;
1023static int kp_cur_row, kp_cur_col;
1024static int kp_scancode;
1025static int kp_stable;
1026static int kp_repeat;
1027static int kp_repeat_time;
1028static int kp_force_time;
1029static int kp_idle_time;
1030
1031static void kp_do_poll(void)
1032{
1033 unsigned int col_mask;
1034 int col;
1035
1036 switch (kp_state) {
1037 case SCAN:
1038 if (kp_idle_time > 0) {
1039 kp_idle_time -= PHONE_CONSOLE_POLL_HZ;
1040 if (kp_idle_time <= 0)
1041 scancode_action(KP_IDLE);
1042 }
1043
1044 col_mask = kp_get_col_mask(KP_ROWS_MASK);
1045 if (col_mask == KP_COLS_MASK)
1046 break;
1047 kp_last_col_mask = col_mask;
1048 kp_stable = 0;
1049 kp_state = SCAN_FILTER;
1050 break;
1051
1052 case SCAN_FILTER:
1053 col_mask = kp_get_col_mask(KP_ROWS_MASK);
1054 if (col_mask != kp_last_col_mask) {
1055 kp_state = SCAN;
1056 break;
1057 }
1058
1059 kp_stable += PHONE_CONSOLE_POLL_HZ;
1060 if (kp_stable < KP_STABLE_HZ)
1061 break;
1062
1063 kp_cur_row = 0;
1064 kp_stable = 0;
1065 kp_state = SCAN_COL;
1066
1067 (void)kp_get_col_mask(1 << kp_cur_row);
1068 break;
1069
1070 case SCAN_COL:
1071 col_mask = kp_get_col_mask(1 << kp_cur_row);
1072 if (col_mask == KP_COLS_MASK) {
1073 if (++kp_cur_row >= KP_ROWS) {
1074 kp_state = SCAN;
1075 break;
1076 }
1077 kp_get_col_mask(1 << kp_cur_row);
1078 break;
1079 }
1080 kp_last_col_mask = col_mask;
1081 kp_stable = 0;
1082 kp_state = SCAN_COL_FILTER;
1083 break;
1084
1085 case SCAN_COL_FILTER:
1086 col_mask = kp_get_col_mask(1 << kp_cur_row);
1087 if (col_mask != kp_last_col_mask || col_mask == KP_COLS_MASK) {
1088 kp_state = SCAN;
1089 break;
1090 }
1091
1092 kp_stable += PHONE_CONSOLE_POLL_HZ;
1093 if (kp_stable < KP_STABLE_HZ)
1094 break;
1095
1096 for (col = 0; col < KP_COLS; col++)
1097 if ((col_mask & (1 << col)) == 0)
1098 break;
1099 kp_cur_col = col;
1100 kp_state = PRESSED;
1101 kp_scancode = kp_scancodes[kp_cur_row * KP_COLS + kp_cur_col];
1102 kp_repeat = kp_repeats[kp_cur_row * KP_COLS + kp_cur_col];
1103
1104 if (kp_repeat)
1105 kp_repeat_time = KP_REPEAT_DELAY_HZ;
1106 kp_force_time = KP_FORCE_DELAY_HZ;
1107
1108 scancode_action(kp_scancode);
1109
1110 break;
1111
1112 case PRESSED:
1113 col_mask = kp_get_col_mask(1 << kp_cur_row);
1114 if (col_mask != kp_last_col_mask) {
1115 kp_state = SCAN;
1116 scancode_action(KP_RELEASE);
1117 kp_idle_time = KP_IDLE_DELAY_HZ;
1118 break;
1119 }
1120
1121 if (kp_repeat) {
1122 kp_repeat_time -= PHONE_CONSOLE_POLL_HZ;
1123 if (kp_repeat_time <= 0) {
1124 kp_repeat_time += KP_REPEAT_HZ;
1125 scancode_action(kp_scancode);
1126 }
1127 }
1128
1129 if (kp_force_time > 0) {
1130 kp_force_time -= PHONE_CONSOLE_POLL_HZ;
1131 if (kp_force_time <= 0)
1132 scancode_action(KP_FORCE);
1133 }
1134
1135 break;
1136 }
1137}
1138
1139
1140
1141int drv_phone_is_idle(void)
1142{
1143 return kp_state == SCAN;
1144}
1145