source: SVN/rincon/u-boot/board/netphone/phone_console.c @ 55

Last change on this file since 55 was 55, checked in by Tim Harvey, 22 months ago

rincon: added latest u-boot source

restored form server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 23.8 KB
Line 
1/*
2 * (C) Copyright 2004 Intracom S.A.
3 * Pantelis Antoniou <panto@intracom.gr>
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24/*
25 * phone_console.c
26 *
27 * A phone based console
28 *
29 * Virtual display of 80x24 characters.
30 * The actual display is much smaller and panned to show the virtual one.
31 * Input is made by a numeric keypad utilizing the input method of
32 * mobile phones. Sorry no T9 lexicons...
33 *
34 */
35
36#include <common.h>
37
38#include <version.h>
39#include <linux/types.h>
40#include <devices.h>
41
42#include <sed156x.h>
43
44/*************************************************************************************************/
45
46#define ROWS    24
47#define COLS    80
48
49#define REFRESH_HZ              (CFG_HZ/50)     /* refresh every 20ms */
50#define BLINK_HZ                (CFG_HZ/2)      /* cursor blink every 500ms */
51
52/*************************************************************************************************/
53
54#define DISPLAY_BACKLIT_PORT    ((volatile immap_t *)CFG_IMMR)->im_ioport.iop_pcdat
55#define DISPLAY_BACKLIT_MASK    0x0010
56
57/*************************************************************************************************/
58
59#define KP_STABLE_HZ            (CFG_HZ/100)    /* stable for 10ms */
60#define KP_REPEAT_DELAY_HZ      (CFG_HZ/4)      /* delay before repeat 250ms */
61#define KP_REPEAT_HZ            (CFG_HZ/20)     /* repeat every 50ms */
62#define KP_FORCE_DELAY_HZ       (CFG_HZ/2)      /* key was force pressed */
63#define KP_IDLE_DELAY_HZ        (CFG_HZ/2)      /* key was released and idle */
64
65#if CONFIG_NETPHONE_VERSION == 1
66#define KP_SPI_RXD_PORT (((volatile immap_t *)CFG_IMMR)->im_ioport.iop_pcdat)
67#define KP_SPI_RXD_MASK 0x0008
68
69#define KP_SPI_TXD_PORT (((volatile immap_t *)CFG_IMMR)->im_ioport.iop_pcdat)
70#define KP_SPI_TXD_MASK 0x0004
71
72#define KP_SPI_CLK_PORT (((volatile immap_t *)CFG_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 *)CFG_IMMR)->im_cpm.cp_pbdat)
76#define KP_SPI_RXD_MASK 0x00000008
77
78#define KP_SPI_TXD_PORT (((volatile immap_t *)CFG_IMMR)->im_cpm.cp_pbdat)
79#define KP_SPI_TXD_MASK 0x00000004
80
81#define KP_SPI_CLK_PORT (((volatile immap_t *)CFG_IMMR)->im_cpm.cp_pbdat)
82#define KP_SPI_CLK_MASK 0x00000002
83#endif
84
85#define KP_CS_PORT      (((volatile immap_t *)CFG_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()      /* no 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       /* leftmost dot (tab)   */
131#define KP_F2   1       /* middle left dot      */
132#define KP_F3   2       /* up                   */
133#define KP_F4   3       /* middle right dot     */
134#define KP_F5   4       /* rightmost dot        */
135#define KP_F6   5       /* C                    */
136#define KP_F7   6       /* left                 */
137#define KP_F8   7       /* down                 */
138#define KP_F9   8       /* right                */
139#define KP_F10  9       /* enter                */
140#define KP_F11  10      /* R                    */
141#define KP_F12  11      /* save                 */
142#define KP_F13  12      /* redial               */
143#define KP_F14  13      /* speaker              */
144#define KP_F15  14      /* unused               */
145#define KP_F16  15      /* unused               */
146
147#define KP_RELEASE              -1      /* key depressed                                */
148#define KP_FORCE                -2      /* key was pressed for more than force hz       */
149#define KP_IDLE                 -3      /* key was released and idle                    */
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/* the simulated vty buffer */
173static char vty_buf[ROWS * COLS];
174static char last_visible_buf[ROWS * COLS];      /* worst case */
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/* per mode character select (for 2-9) */
199static const char *digits_sel[2][8] = {
200        {       /* small */
201                "abc2",                                 /* 2 */
202                "def3",                                 /* 3 */
203                "ghi4",                                 /* 4 */
204                "jkl5",                                 /* 5 */
205                "mno6",                                 /* 6 */
206                "pqrs7",                                /* 7 */
207                "tuv8",                                 /* 8 */
208                "wxyz9",                                /* 9 */
209        }, {    /* capital */
210                "ABC2",                                 /* 2 */
211                "DEF3",                                 /* 3 */
212                "GHI4",                                 /* 4 */
213                "JKL5",                                 /* 5 */
214                "MNO6",                                 /* 6 */
215                "PQRS7",                                /* 7 */
216                "TUV8",                                 /* 8 */
217                "WXYZ9",                                /* 9 */
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/* flush buffers */
269int phone_start(void)
270{
271        console_init();
272
273        update();
274        sed156x_sync();
275
276        enabled = 1;
277        queued_char = 'U' - '@';
278
279        /* backlit on */
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        /* backlit off */
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        device_t 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;        /* Video extensions */
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;  /* 'putc' function */
339        console_dev.puts = phone_puts;  /* 'puts' function */
340        console_dev.tstc = phone_tstc;  /* 'tstc' function */
341        console_dev.getc = phone_getc;  /* 'getc' function */
342
343        if (device_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                /* do the blink */
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                /* do the refresh */
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                        /* key was released */
440                case KP_RELEASE:
441                        forced_scancode = 0;
442                        break;
443
444                        /* key was forced */
445                case KP_FORCE:
446
447                        switch (last_scancode) {
448                                case '#':
449                                        if (input_mode == IM_NUMBER) {
450                                                input_mode = IM_CAPITAL;
451                                                /* queue backspace to erase # */
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                        /* release and idle */
480                case KP_IDLE:
481                        input_scancode = -1;
482                        if (input_state < 0)
483                                break;
484                        terminate_input();
485                        break;
486
487                        /* change input mode */
488                case '#':
489                        if (last_scancode == '#')       /* no repeat */
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                        /* no repeat */
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                        /* no repeat */
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                        /* move visible display */
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                                        /* up */
582                                case KP_F3:
583                                        if (new_disp_row <= 0)
584                                                break;
585                                        new_disp_row--;
586                                        break;
587
588                                        /* down */
589                                case KP_F8:
590                                        if (new_disp_row >= ROWS - height)
591                                                break;
592                                        new_disp_row++;
593                                        break;
594
595                                        /* left */
596                                case KP_F7:
597                                        if (new_disp_col <= 0)
598                                                break;
599                                        new_disp_col--;
600                                        break;
601
602                                        /* right */
603                                case KP_F9:
604                                        if (new_disp_col >= COLS - width)
605                                                break;
606                                        new_disp_col++;
607                                        break;
608                        }
609
610                        /* no change? */
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:     /* backspace */
621                        /* inputing something; no backspace sent, just cancel input */
622                        if (input_state >= 0) {
623                                input_selected_char = -1;       /* cancel */
624                                terminate_input();
625                                break;
626                        }
627                        queue_input_char('\b');
628                        break;
629
630                case KP_F10:    /* enter */
631                        /* inputing something; first cancel input */
632                        if (input_state >= 0)
633                                terminate_input();
634                        queue_input_char('\r');
635                        break;
636
637                case KP_F11:    /* R -> Ctrl-C (abort) */
638                        if (input_state >= 0)
639                                terminate_input();
640                        queue_input_char('C' - 'Q');    /* ctrl-c */
641                        break;
642
643                case KP_F5:     /* F% -> Ctrl-U (clear line) */
644                        if (input_state >= 0)
645                                terminate_input();
646                        queue_input_char('U' - 'Q');    /* ctrl-c */
647                        break;
648
649
650                case KP_F1:     /* tab */
651                        /* inputing something; first cancel input */
652                        if (input_state >= 0)
653                                terminate_input();
654                        queue_input_char('\t');
655                        break;
656
657                case KP_F2:     /* change fast punct */
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)        /* don't record forced or idle scancode */
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/* update the display; make sure to update only the differences */
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        /* printf("(%d,%d) (%d,%d) %s\n", curs_col, curs_row, disp_col, disp_row, cp ? "YES" : "no"); */
730
731        /* clear previous cursor */
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                /* update only the differences */
743                do {
744                        while (s < e && *s == *t) {
745                                s++;
746                                t++;
747                        }
748                        if (s == e)     /* no more */
749                                break;
750
751                        /* find run */
752                        r = s;
753                        while (s < e && *s != *t)
754                                *t++ = *s++;
755
756                        /* and update */
757                        sed156x_output_at(r - b, i, r, s - r);
758
759                } while (s < e);
760
761                b += COLS;
762        }
763
764        /* set cursor */
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/* ensure visibility; the trick is to minimize the screen movement */
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        /* clamp visible region */
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        /* move to easier to use vars */
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        /* printf("(%d,%d) - (%d,%d) : (%d, %d) - (%d, %d)\n", x1, y1, x2, y2, a1, b1, a2, b2); */
812
813        if (a2 > x2) {
814                /* move to the right */
815                x2 = a2;
816                x1 = x2 - width;
817                if (x1 < 0) {
818                        x1 = 0;
819                        x2 = width;
820                }
821        } else if (a1 < x1) {
822                /* move to the left */
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                /* move down */
833                y2 = b2;
834                y1 = y2 - height;
835                if (y1 < 0) {
836                        y1 = 0;
837                        y2 = height;
838                }
839        } else if (b1 < y1) {
840                /* move up */
841                y1 = b1;
842                y2 = y1 + width;
843                if (y2 > ROWS) {
844                        y2 = ROWS;
845                        y1 = y2 - height;
846                }
847        }
848
849        /* printf("(%d,%d) - (%d,%d) : (%d, %d) - (%d, %d)\n", x1, y1, x2, y2, a1, b1, a2, b2); */
850
851        /* no movement? */
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':              /* ignore bell            */
888                case '\r':              /* ignore carriage return */
889                        break;
890
891                case '\n':              /* next line */
892                        newline();
893                        ensure_visible(curs_col, curs_row, 1, 1);
894                        break;
895
896                case 9: /* tab 8 */
897                        /* move to tab */
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:         /* backspace */
911                        if (curs_col <= 0)
912                                break;
913                        curs_col--;
914
915                        /* make sure that we see a couple of characters before */
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:                /* draw the char */
924                        putchar_at_cursor(c);
925
926                        /*
927                         * check for newline
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 *)CFG_IMMR)->im_cpm.cp_pedat & 0x0f;
987        /* XXX FUCK FUCK FUCK FUCK FUCK!!!! */
988        col_mask = ((col_mask & 0x08) >> 3) |   /* BKBR1 */
989                   ((col_mask & 0x04) << 1) |   /* BKBR2 */
990                    (col_mask & 0x02) |         /* BKBR3 */
991                   ((col_mask & 0x01) << 2);    /* BKBR4 */
992
993#endif
994        /* printf("col_mask(row_mask = 0x%x) -> col_mask = 0x%x\n", row_mask, col_mask); */
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;  /* nothing */
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}
Note: See TracBrowser for help on using the repository browser.