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