1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  PC-style keyboard interface		File: KBD_SUBR.C
5    *
6    *  This module converts a stream of scancodes into ASCII
7    *  characters.  The scan codes come from a PC-style
8    *  keyboard.
9    *
10    *  Author:  Mitch Lichtenberg
11    *
12    *********************************************************************
13    *
14    *  Copyright 2000,2001,2002,2003
15    *  Broadcom Corporation. All rights reserved.
16    *
17    *  This software is furnished under license and may be used and
18    *  copied only in accordance with the following terms and
19    *  conditions.  Subject to these conditions, you may download,
20    *  copy, install, use, modify and distribute modified or unmodified
21    *  copies of this software in source and/or binary form.  No title
22    *  or ownership is transferred hereby.
23    *
24    *  1) Any source code used, modified or distributed must reproduce
25    *     and retain this copyright notice and list of conditions
26    *     as they appear in the source file.
27    *
28    *  2) No right is granted to use any trade name, trademark, or
29    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
30    *     name may not be used to endorse or promote products derived
31    *     from this software without the prior written permission of
32    *     Broadcom Corporation.
33    *
34    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
35    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
36    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
37    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
38    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
39    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
40    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
42    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
44    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
45    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
46    *     THE POSSIBILITY OF SUCH DAMAGE.
47    ********************************************************************* */
48
49
50#include "lib_types.h"
51#include "lib_string.h"
52
53#include "kbd_subr.h"
54
55
56/*  *********************************************************************
57    *  Constants
58    ********************************************************************* */
59
60#define FLG_SCROLL          0x0001  /* Toggles: same as bit positions for LEDs! */
61#define FLG_NUM             0x0002
62#define FLG_CAPS            0x0004
63#define FLG_SHIFT           0x0008  /* Shifts */
64#define FLG_CTRL            0x0100
65#define FLG_ALT             0x0200
66#define FLG_FKEY            0x0400  /* function keys */
67#define FLG_NKPD            0x0800  /* numeric keypad */
68#define FLG_ASCII           0x1000  /* regular ASCII character */
69#define FLG_NONE            0x2000
70#define FLG_BREAKBIT        0x80
71
72
73/*  *********************************************************************
74    *  Structures
75    ********************************************************************* */
76
77#define KC_RESPLEN 4
78typedef struct keycode_s {
79    int         kc_type;
80    char        kc_normal[KC_RESPLEN];
81    char        kc_shifted[KC_RESPLEN];
82    char        kc_ctrl[KC_RESPLEN];
83} keycode_t;
84
85
86/*  *********************************************************************
87    *  Scan code conversion table
88    ********************************************************************* */
89
90static keycode_t scantable[] = {
91    { FLG_NONE,   "",             "",             "" },           /* 0 */
92    { FLG_ASCII,  "\033",         "\033",         "\033" },       /* 1 ESC */
93    { FLG_ASCII,  "1",            "!",            "!" },          /* 2 1 */
94    { FLG_ASCII,  "2",            "@",            "\000" },       /* 3 2 */
95    { FLG_ASCII,  "3",            "#",            "#" },          /* 4 3 */
96    { FLG_ASCII,  "4",            "$",            "$" },          /* 5 4 */
97    { FLG_ASCII,  "5",            "%",            "%" },          /* 6 5 */
98    { FLG_ASCII,  "6",            "^",            "\036" },       /* 7 6 */
99    { FLG_ASCII,  "7",            "&",            "&" },          /* 8 7 */
100    { FLG_ASCII,  "8",            "*",            "\010" },       /* 9 8 */
101    { FLG_ASCII,  "9",            "(",            "(" },          /* 10 9 */
102    { FLG_ASCII,  "0",            ")",            ")" },          /* 11 0 */
103    { FLG_ASCII,  "-",            "_",            "\037" },       /* 12 - */
104    { FLG_ASCII,  "=",            "+",            "+" },          /* 13 = */
105    { FLG_ASCII,  "\177",         "\177",         "\010" },       /* 14 <- */
106    { FLG_ASCII,  "\t",           "\177\t",       "\t" },         /* 15 ->| */
107    { FLG_ASCII,  "q",            "Q",            "\021" },       /* 16 q */
108    { FLG_ASCII,  "w",            "W",            "\027" },       /* 17 w */
109    { FLG_ASCII,  "e",            "E",            "\005" },       /* 18 e */
110    { FLG_ASCII,  "r",            "R",            "\022" },       /* 19 r */
111    { FLG_ASCII,  "t",            "T",            "\024" },       /* 20 t */
112    { FLG_ASCII,  "y",            "Y",            "\031" },       /* 21 y */
113    { FLG_ASCII,  "u",            "U",            "\025" },       /* 22 u */
114    { FLG_ASCII,  "i",            "I",            "\011" },       /* 23 i */
115    { FLG_ASCII,  "o",            "O",            "\017" },       /* 24 o */
116    { FLG_ASCII,  "p",            "P",            "\020" },       /* 25 p */
117    { FLG_ASCII,  "[",            "{",            "\033" },       /* 26 [ */
118    { FLG_ASCII,  "]",            "}",            "\035" },       /* 27 ] */
119    { FLG_ASCII,  "\r",           "\r",           "\n" },         /* 28 ENT */
120    { FLG_CTRL,    "",             "",             "" },          /* 29 CTRL */
121    { FLG_ASCII,  "a",            "A",            "\001" },       /* 30 a */
122    { FLG_ASCII,  "s",            "S",            "\023" },       /* 31 s */
123    { FLG_ASCII,  "d",            "D",            "\004" },       /* 32 d */
124    { FLG_ASCII,  "f",            "F",            "\006" },       /* 33 f */
125    { FLG_ASCII,  "g",            "G",            "\007" },       /* 34 g */
126    { FLG_ASCII,  "h",            "H",            "\010" },       /* 35 h */
127    { FLG_ASCII,  "j",            "J",            "\n" },         /* 36 j */
128    { FLG_ASCII,  "k",            "K",            "\013" },       /* 37 k */
129    { FLG_ASCII,  "l",            "L",            "\014" },       /* 38 l */
130    { FLG_ASCII,  ";",            ":",            ";" },          /* 39 ; */
131    { FLG_ASCII,  "'",            "\"",           "'" },          /* 40 ' */
132    { FLG_ASCII,  "`",            "~",            "`" },          /* 41 ` */
133    { FLG_SHIFT,  "",             "",             "" },           /* 42 SHIFT */
134    { FLG_ASCII,  "\\",           "|",            "\034" },       /* 43 \ */
135    { FLG_ASCII,  "z",            "Z",            "\032" },       /* 44 z */
136    { FLG_ASCII,  "x",            "X",            "\030" },       /* 45 x */
137    { FLG_ASCII,  "c",            "C",            "\003" },       /* 46 c */
138    { FLG_ASCII,  "v",            "V",            "\026" },       /* 47 v */
139    { FLG_ASCII,  "b",            "B",            "\002" },       /* 48 b */
140    { FLG_ASCII,  "n",            "N",            "\016" },       /* 49 n */
141    { FLG_ASCII,  "m",            "M",            "\r" },         /* 50 m */
142    { FLG_ASCII,  ",",            "<",            "<" },          /* 51 , */
143    { FLG_ASCII,  ".",            ">",            ">" },          /* 52 . */
144    { FLG_ASCII,  "/",            "?",            "\037" },       /* 53 / */
145    { FLG_SHIFT,  "",             "",             "" },           /* 54 SHIFT */
146    { FLG_NKPD,   "*",            "*",            "*" },          /* 55 KP* */
147    { FLG_ALT,    "",             "",             "" },           /* 56 ALT */
148    { FLG_ASCII,  " ",            " ",            "\000" },       /* 57 SPC */
149    { FLG_CAPS,   "",             "",             "" },           /* 58 CAPS */
150    { FLG_FKEY,   "\033[M",       "\033[Y",       "\033[k" },     /* 59 f1 */
151    { FLG_FKEY,   "\033[N",       "\033[Z",       "\033[l" },     /* 60 f2 */
152    { FLG_FKEY,   "\033[O",       "\033[a",       "\033[m" },     /* 61 f3 */
153    { FLG_FKEY,   "\033[P",       "\033[b",       "\033[n" },     /* 62 f4 */
154    { FLG_FKEY,   "\033[Q",       "\033[c",       "\033[o" },     /* 63 f5 */
155    { FLG_FKEY,   "\033[R",       "\033[d",       "\033[p" },     /* 64 f6 */
156    { FLG_FKEY,   "\033[S",       "\033[e",       "\033[q" },     /* 65 f7 */
157    { FLG_FKEY,   "\033[T",       "\033[f",       "\033[r" },     /* 66 f8 */
158    { FLG_FKEY,   "\033[U",       "\033[g",       "\033[s" },     /* 67 f9 */
159    { FLG_FKEY,   "\033[V",       "\033[h",       "\033[t" },     /* 68 f10 */
160    { FLG_NUM,    "",             "",             "" },           /* 69 NUMLK */
161    { FLG_SCROLL, "",             "",             "" },           /* 70 SCRLK  */
162    { FLG_NKPD,   "7",            "\033[H",       "7" },          /* 71 KP7 */
163    { FLG_NKPD,   "8",            "\033[A",       "8" },          /* 72 KP8 */
164    { FLG_NKPD,   "9",            "\033[I",       "9" },          /* 73 KP9 */
165    { FLG_NKPD,   "-",            "-",            "-" },          /* 74 KP- */
166    { FLG_NKPD,   "4",            "\033[D",       "4" },          /* 75 KP4 */
167    { FLG_NKPD,   "5",            "\033[E",       "5" },          /* 76 KP5 */
168    { FLG_NKPD,   "6",            "\033[C",       "6" },          /* 77 KP6 */
169    { FLG_NKPD,   "+",            "+",            "+" },          /* 78 KP+ */
170    { FLG_NKPD,   "1",            "\033[F",       "1" },          /* 79 KP1 */
171    { FLG_NKPD,   "2",            "\033[B",       "2" },          /* 80 KP2 */
172    { FLG_NKPD,   "3",            "\033[G",       "3" },          /* 81 KP3 */
173    { FLG_NKPD,   "0",            "\033[L",       "0" },          /* 82 KP0 */
174    { FLG_NKPD,   ".",            "\177",         "." },          /* 83 KP. */
175    { FLG_NONE,   "",             "",             "" },           /* 84 0 */
176    { FLG_NONE,   "100",          "",             "" },           /* 85 0 */
177    { FLG_NONE,   "101",          "",             "" },           /* 86 0 */
178    { FLG_FKEY,   "\033[W",       "\033[i",       "\033[u" },     /* 87 f11 */
179    { FLG_FKEY,   "\033[X",       "\033[j",       "\033[v" },     /* 88 f12 */
180    { FLG_NONE,   "102",          "",             "" },           /* 89 0 */
181    { FLG_NONE,   "103",          "",             "" },           /* 90 0 */
182    { FLG_NONE,   "",             "",             "" },           /* 91 0 */
183    { FLG_NONE,   "",             "",             "" },           /* 92 0 */
184    { FLG_NONE,   "",             "",             "" },           /* 93 0 */
185    { FLG_NONE,   "",             "",             "" },           /* 94 0 */
186    { FLG_NONE,   "",             "",             "" },           /* 95 0 */
187    { FLG_NONE,   "",             "",             "" },           /* 96 0 */
188    { FLG_NONE,   "",             "",             "" },           /* 97 0 */
189    { FLG_NONE,   "",             "",             "" },           /* 98 0 */
190    { FLG_NONE,   "",             "",             "" },           /* 99 0 */
191    { FLG_NONE,   "",             "",             "" },           /* 100 */
192    { FLG_NONE,   "",             "",             "" },           /* 101 */
193    { FLG_NONE,   "",             "",             "" },           /* 102 */
194    { FLG_NONE,   "",             "",             "" },           /* 103 */
195    { FLG_NONE,   "",             "",             "" },           /* 104 */
196    { FLG_NONE,   "",             "",             "" },           /* 105 */
197    { FLG_NONE,   "",             "",             "" },           /* 106 */
198    { FLG_NONE,   "",             "",             "" },           /* 107 */
199    { FLG_NONE,   "",             "",             "" },           /* 108 */
200    { FLG_NONE,   "",             "",             "" },           /* 109 */
201    { FLG_NONE,   "",             "",             "" },           /* 110 */
202    { FLG_NONE,   "",             "",             "" },           /* 111 */
203    { FLG_NONE,   "",             "",             "" },           /* 112 */
204    { FLG_NONE,   "",             "",             "" },           /* 113 */
205    { FLG_NONE,   "",             "",             "" },           /* 114 */
206    { FLG_NONE,   "",             "",             "" },           /* 115 */
207    { FLG_NONE,   "",             "",             "" },           /* 116 */
208    { FLG_NONE,   "",             "",             "" },           /* 117 */
209    { FLG_NONE,   "",             "",             "" },           /* 118 */
210    { FLG_NONE,   "",             "",             "" },           /* 119 */
211    { FLG_NONE,   "",             "",             "" },           /* 120 */
212    { FLG_NONE,   "",             "",             "" },           /* 121 */
213    { FLG_NONE,   "",             "",             "" },           /* 122 */
214    { FLG_NONE,   "",             "",             "" },           /* 123 */
215    { FLG_NONE,   "",             "",             "" },           /* 124 */
216    { FLG_NONE,   "",             "",             "" },           /* 125 */
217    { FLG_NONE,   "",             "",             "" },           /* 126 */
218    { FLG_NONE,   "",             "",             "" },           /* 127 */
219};
220
221
222/*  *********************************************************************
223    *  KBD_ENQUEUECHAR(ks,ch)
224    *
225    *  Put a character on the queue
226    *
227    *  Input parameters:
228    *  	   ks - keyboard state
229    *  	   ch - character to enqueue
230    *
231    *  Return value:
232    *  	   nothing
233    ********************************************************************* */
234
235static void kbd_enqueuechar(keystate_t *ks,char ch)
236{
237    if (((ks->ks_head+1) & (KEYQUEUELEN-1)) == ks->ks_tail) {
238	/* queue is full */
239	return;
240	}
241    ks->ks_queue[ks->ks_head] = ch;
242    ks->ks_head = (ks->ks_head+1) & (KEYQUEUELEN-1);
243}
244
245
246/*  *********************************************************************
247    *  KBD_DEQUEUECHAR(ks)
248    *
249    *  Remove a character from the queue
250    *
251    *  Input parameters:
252    *  	   ks - keystate
253    *
254    *  Return value:
255    *  	   0 if no characters in queue
256    *  	   else character from queue
257    ********************************************************************* */
258static int kbd_dequeuechar(keystate_t *ks)
259{
260    char ch;
261
262    if (ks->ks_head == ks->ks_tail) return 0;
263
264    ch = ks->ks_queue[ks->ks_tail];
265    ks->ks_tail = (ks->ks_tail+1) & (KEYQUEUELEN-1);
266    return ch;
267}
268
269/*  *********************************************************************
270    *  KBD_READ(ks)
271    *
272    *  User call to kbd_dequeuechar - remove a character from
273    *  the queue.
274    *
275    *  Input parameters:
276    *  	   ks - keyboard state
277    *
278    *  Return value:
279    *  	   character from queue or 0 if no chars
280    ********************************************************************* */
281
282int kbd_read(keystate_t *ks)
283{
284    return kbd_dequeuechar(ks);
285}
286
287/*  *********************************************************************
288    *  KBD_INPSTAT(ks)
289    *
290    *  Test input status (see if a character is waiting)
291    *
292    *  Input parameters:
293    *  	   ks - keyboard state
294    *
295    *  Return value:
296    *  	   0 if no chars waiting, 1 if characters are waiting
297    ********************************************************************* */
298
299int kbd_inpstat(keystate_t *ks)
300{
301    return (ks->ks_head != ks->ks_tail);
302}
303
304
305/*  *********************************************************************
306    *  KBD_DOSCAN(ks,scan)
307    *
308    *  Process a scan code from the keyboard.
309    *
310    *  Input parameters:
311    *  	   ks - keyboard state
312    *  	   scan - scan code from the keyboard
313    *
314    *  Return value:
315    *  	   nothing
316    ********************************************************************* */
317
318void kbd_doscan(keystate_t *ks,uint8_t scan)
319{
320    int breakflg;
321    keycode_t *code = 0;
322    char *str;
323
324    breakflg = (scan & FLG_BREAKBIT);
325    scan &= ~FLG_BREAKBIT;
326    code = &scantable[scan];
327
328    if (code->kc_type & (FLG_SHIFT|FLG_CTRL|FLG_ALT)) {
329	if (breakflg) ks->ks_shiftflags &= ~code->kc_type;
330	else ks->ks_shiftflags |= code->kc_type;
331	}
332    if (code->kc_type & (FLG_CAPS|FLG_SCROLL|FLG_NUM)) {
333	if (!breakflg) ks->ks_shiftflags ^= code->kc_type;
334	if (ks->ks_setleds) {
335	    (*(ks->ks_setleds))(ks,ks->ks_shiftflags & (FLG_CAPS|FLG_SCROLL|FLG_NUM));
336	    }
337	}
338    if (code->kc_type & (FLG_ASCII | FLG_FKEY | FLG_NKPD)) {
339	if (ks->ks_shiftflags & (FLG_SHIFT|FLG_CAPS)) str = code->kc_shifted;
340	else if (ks->ks_shiftflags & FLG_CTRL) str = code->kc_ctrl;
341	else str = code->kc_normal;
342	if (!breakflg) {
343	    while (*str) {
344		kbd_enqueuechar(ks,*str++);
345		}
346	    }
347	}
348}
349
350
351/*  *********************************************************************
352    *  KBD_INIT(ks,setleds,ref)
353    *
354    *  Initialize a keyboard state object.
355    *
356    *  Input parameters:
357    *  	   ks - keyboard state
358    *  	   setleds - routine to call when we want to set the state
359    *  	             of the keyboard's LEDs
360    *  	   ref - data to store in the keyboard state object
361    *
362    *  Return value:
363    *  	   nothing
364    ********************************************************************* */
365
366void kbd_init(keystate_t *ks,int (*setleds)(keystate_t *,int),void *ref)
367{
368    memset(ks,0,sizeof(keystate_t));
369    ks->ks_setleds = setleds;
370    ks->ks_ref = ref;
371}
372