1/* 2 * Kernel Debugger Architecture Dependent Console I/O handler 3 * 4 * This file is subject to the terms and conditions of the GNU General Public 5 * License. 6 * 7 * Copyright (c) 1999-2006 Silicon Graphics, Inc. All Rights Reserved. 8 * Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved. 9 */ 10 11#include <linux/kdb.h> 12#include <linux/keyboard.h> 13#include <linux/ctype.h> 14#include <linux/module.h> 15#include <linux/io.h> 16 17/* Keyboard Controller Registers on normal PCs. */ 18 19#define KBD_STATUS_REG 0x64 /* Status register (R) */ 20#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ 21 22/* Status Register Bits */ 23 24#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ 25#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ 26 27static int kbd_exists; 28static int kbd_last_ret; 29 30/* 31 * Check if the keyboard controller has a keypress for us. 32 * Some parts (Enter Release, LED change) are still blocking polled here, 33 * but hopefully they are all short. 34 */ 35int kdb_get_kbd_char(void) 36{ 37 int scancode, scanstatus; 38 static int shift_lock; /* CAPS LOCK state (0-off, 1-on) */ 39 static int shift_key; /* Shift next keypress */ 40 static int ctrl_key; 41 u_short keychar; 42 43 if (KDB_FLAG(NO_I8042) || KDB_FLAG(NO_VT_CONSOLE) || 44 (inb(KBD_STATUS_REG) == 0xff && inb(KBD_DATA_REG) == 0xff)) { 45 kbd_exists = 0; 46 return -1; 47 } 48 kbd_exists = 1; 49 50 if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) 51 return -1; 52 53 /* 54 * Fetch the scancode 55 */ 56 scancode = inb(KBD_DATA_REG); 57 scanstatus = inb(KBD_STATUS_REG); 58 59 /* 60 * Ignore mouse events. 61 */ 62 if (scanstatus & KBD_STAT_MOUSE_OBF) 63 return -1; 64 65 /* 66 * Ignore release, trigger on make 67 * (except for shift keys, where we want to 68 * keep the shift state so long as the key is 69 * held down). 70 */ 71 72 if (((scancode&0x7f) == 0x2a) || ((scancode&0x7f) == 0x36)) { 73 /* 74 * Next key may use shift table 75 */ 76 if ((scancode & 0x80) == 0) 77 shift_key = 1; 78 else 79 shift_key = 0; 80 return -1; 81 } 82 83 if ((scancode&0x7f) == 0x1d) { 84 /* 85 * Left ctrl key 86 */ 87 if ((scancode & 0x80) == 0) 88 ctrl_key = 1; 89 else 90 ctrl_key = 0; 91 return -1; 92 } 93 94 if ((scancode & 0x80) != 0) { 95 if (scancode == 0x9c) 96 kbd_last_ret = 0; 97 return -1; 98 } 99 100 scancode &= 0x7f; 101 102 /* 103 * Translate scancode 104 */ 105 106 if (scancode == 0x3a) { 107 /* 108 * Toggle caps lock 109 */ 110 shift_lock ^= 1; 111 112#ifdef KDB_BLINK_LED 113 kdb_toggleled(0x4); 114#endif 115 return -1; 116 } 117 118 if (scancode == 0x0e) { 119 /* 120 * Backspace 121 */ 122 return 8; 123 } 124 125 /* Special Key */ 126 switch (scancode) { 127 case 0xF: /* Tab */ 128 return 9; 129 case 0x53: /* Del */ 130 return 4; 131 case 0x47: /* Home */ 132 return 1; 133 case 0x4F: /* End */ 134 return 5; 135 case 0x4B: /* Left */ 136 return 2; 137 case 0x48: /* Up */ 138 return 16; 139 case 0x50: /* Down */ 140 return 14; 141 case 0x4D: /* Right */ 142 return 6; 143 } 144 145 if (scancode == 0xe0) 146 return -1; 147 148 /* 149 * For Japanese 86/106 keyboards 150 * See comment in drivers/char/pc_keyb.c. 151 * - Masahiro Adegawa 152 */ 153 if (scancode == 0x73) 154 scancode = 0x59; 155 else if (scancode == 0x7d) 156 scancode = 0x7c; 157 158 if (!shift_lock && !shift_key && !ctrl_key) { 159 keychar = plain_map[scancode]; 160 } else if ((shift_lock || shift_key) && key_maps[1]) { 161 keychar = key_maps[1][scancode]; 162 } else if (ctrl_key && key_maps[4]) { 163 keychar = key_maps[4][scancode]; 164 } else { 165 keychar = 0x0020; 166 kdb_printf("Unknown state/scancode (%d)\n", scancode); 167 } 168 keychar &= 0x0fff; 169 if (keychar == '\t') 170 keychar = ' '; 171 switch (KTYP(keychar)) { 172 case KT_LETTER: 173 case KT_LATIN: 174 if (isprint(keychar)) 175 break; /* printable characters */ 176 /* fall through */ 177 case KT_SPEC: 178 if (keychar == K_ENTER) 179 break; 180 /* fall through */ 181 default: 182 return -1; /* ignore unprintables */ 183 } 184 185 if (scancode == 0x1c) { 186 kbd_last_ret = 1; 187 return 13; 188 } 189 190 return keychar & 0xff; 191} 192EXPORT_SYMBOL_GPL(kdb_get_kbd_char); 193 194/* 195 * Best effort cleanup of ENTER break codes on leaving KDB. Called on 196 * exiting KDB, when we know we processed an ENTER or KP ENTER scan 197 * code. 198 */ 199void kdb_kbd_cleanup_state(void) 200{ 201 int scancode, scanstatus; 202 203 /* 204 * Nothing to clean up, since either 205 * ENTER was never pressed, or has already 206 * gotten cleaned up. 207 */ 208 if (!kbd_last_ret) 209 return; 210 211 kbd_last_ret = 0; 212 /* 213 * Enter key. Need to absorb the break code here, lest it gets 214 * leaked out if we exit KDB as the result of processing 'g'. 215 * 216 * This has several interesting implications: 217 * + Need to handle KP ENTER, which has break code 0xe0 0x9c. 218 * + Need to handle repeat ENTER and repeat KP ENTER. Repeats 219 * only get a break code at the end of the repeated 220 * sequence. This means we can't propagate the repeated key 221 * press, and must swallow it away. 222 * + Need to handle possible PS/2 mouse input. 223 * + Need to handle mashed keys. 224 */ 225 226 while (1) { 227 while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) 228 cpu_relax(); 229 230 /* 231 * Fetch the scancode. 232 */ 233 scancode = inb(KBD_DATA_REG); 234 scanstatus = inb(KBD_STATUS_REG); 235 236 /* 237 * Skip mouse input. 238 */ 239 if (scanstatus & KBD_STAT_MOUSE_OBF) 240 continue; 241 242 /* 243 * If we see 0xe0, this is either a break code for KP 244 * ENTER, or a repeat make for KP ENTER. Either way, 245 * since the second byte is equivalent to an ENTER, 246 * skip the 0xe0 and try again. 247 * 248 * If we see 0x1c, this must be a repeat ENTER or KP 249 * ENTER (and we swallowed 0xe0 before). Try again. 250 * 251 * We can also see make and break codes for other keys 252 * mashed before or after pressing ENTER. Thus, if we 253 * see anything other than 0x9c, we have to try again. 254 * 255 * Note, if you held some key as ENTER was depressed, 256 * that break code would get leaked out. 257 */ 258 if (scancode != 0x9c) 259 continue; 260 261 return; 262 } 263} 264