1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Generic keyboard support: translation 29 * 30 * This module is project private. Please see PSARC/1998/176 and 31 * PSARC/1998/026 for references to the kbtrans module. 32 * 33 * It is believed that it is safe to call these functions within debugger mode 34 * except kbtrans_dprintf. Debugger mode is a single threaded mode where most 35 * kernel services are not available, including memory allocation. Debugger 36 * mode is for kmdb and OBP debugging, where the debugger calls back into the 37 * kernel to obtain console input. 38 * 39 * Please be _very_ careful about what external functions you call. 40 */ 41 42 #define KEYMAP_SIZE_VARIABLE 43 44 #include <sys/types.h> 45 #include <sys/cred.h> 46 #include <sys/ddi.h> 47 #include <sys/sunddi.h> 48 #include <sys/kmem.h> 49 #include <sys/kbd.h> 50 #include <sys/cmn_err.h> 51 #include <sys/modctl.h> 52 #include <sys/kbio.h> 53 #include <sys/vuid_event.h> 54 #include <sys/consdev.h> 55 #include <sys/kbtrans.h> 56 #include <sys/errno.h> 57 #include <sys/promif.h> 58 #include <sys/varargs.h> 59 #include "kbtrans_lower.h" 60 61 /* 62 * Internal Function Prototypes 63 */ 64 static boolean_t kbtrans_do_compose(struct kbtrans_lower *, keymap_entry_t, 65 keymap_entry_t, keymap_entry_t *); 66 static void kbtrans_translate(struct kbtrans_lower *, 67 struct keyboard_callback *, kbtrans_key_t, enum keystate); 68 69 /* 70 * kbtrans_processkey: 71 * 72 * lower - state information used by the calling driver 73 * this parameter is passed back to the callback routines. 74 * key - scancode 75 * state - KEY_PRESSED / KEY_RELEASED 76 * 77 * This routine checks to see if there is a raw callback, and calls it 78 * if it exists. If there is no raw callback, the key is translated. 79 * The raw callback allows the driver that called the translation module 80 * to be passed untranslated scancodes. 81 */ 82 void 83 kbtrans_processkey(struct kbtrans_lower *lower, 84 struct keyboard_callback *cb, kbtrans_key_t key, enum keystate state) 85 { 86 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (lower, "kbtrans_processkey: " 87 "newstate=%d key=%d", state, key)); 88 89 /* 90 * If there is a raw routine, then call it and return. 91 */ 92 if (cb->kc_keypressed_raw != NULL) { 93 94 if (state == KEY_PRESSED) { 95 96 cb->kc_keypressed_raw(lower->kbtrans_upper, key); 97 } else { 98 99 cb->kc_keyreleased_raw(lower->kbtrans_upper, key); 100 } 101 102 return; 103 } 104 105 /* 106 * translate the scancode into a key. 107 */ 108 kbtrans_translate(lower, cb, key, state); 109 } 110 111 112 /* 113 * kbtrans_translate: 114 * 115 * lower - state information used by the calling driver 116 * this parameter is passed back to the callback routines. 117 * key - scan code 118 * state - KEY_PRESSED / KEY_RELEASED 119 * 120 * Called to process key events if we are in TR_ASCII or TR_EVENT 121 * (sunview) mode. This routine will call the appropriate translation_callback 122 * for the character when it is done translating it. 123 */ 124 static void 125 kbtrans_translate(struct kbtrans_lower *lower, struct keyboard_callback *cb, 126 kbtrans_key_t key, enum keystate newstate) 127 { 128 unsigned shiftmask; 129 register keymap_entry_t entry; 130 register unsigned entrytype; 131 keymap_entry_t result; 132 keymap_entry_t *ke; 133 int i; 134 boolean_t good_compose; 135 136 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (lower, "KEY TRANSLATE " 137 "newstate=0x%x key=0x%x\n", newstate, key)); 138 139 if (lower->kbtrans_keyboard == NULL) { 140 /* 141 * Nobody has told us about this keyboard yet. 142 */ 143 return; 144 } 145 146 /* 147 * Get the current state of the shiftmask 148 */ 149 shiftmask = lower->kbtrans_shiftmask; 150 151 /* 152 * If the key has been released, then or in the UPMASK flag. 153 */ 154 if (newstate == KEY_RELEASED) 155 shiftmask |= UPMASK; 156 157 /* 158 * Based on the shiftmask, lookup the keymap entry that we should 159 * be using for this scancode. 160 */ 161 ke = kbtrans_find_entry(lower, shiftmask, key); 162 163 if (ke == NULL) { 164 /* 165 * This is a gross error. Cancel the repeat key and exit, 166 * we can not translate this scancode. 167 */ 168 cb->kc_cancel_repeat(lower->kbtrans_upper); 169 170 return; 171 } 172 173 /* 174 * Get the key for this scancode. 175 */ 176 entry = *ke; 177 178 if (entry == NONL) { 179 /* 180 * NONL appears only in the Num Lock table, and indicates that 181 * this key is not affected by Num Lock. This means we should 182 * ask for the table we would have gotten had Num Lock not been 183 * down, and translate using that table. 184 */ 185 ke = kbtrans_find_entry(lower, shiftmask & ~NUMLOCKMASK, key); 186 187 if (ke == NULL) { 188 /* 189 * This is a gross error. Cancel the repeat key and 190 * exit, we can not translate this scancode. 191 */ 192 cb->kc_cancel_repeat(lower->kbtrans_upper); 193 194 return; 195 } 196 197 /* 198 * Get the new key for this scancode. 199 */ 200 entry = *ke; 201 } 202 203 /* 204 * The entrytype indicates what category of key we are processing. 205 * Categories include shift keys, function keys, and numeric keypad 206 * keys. 207 */ 208 entrytype = KEYFLAGS(entry); 209 210 if (entrytype == SHIFTKEYS) { 211 /* 212 * Handle the state of toggle shifts specially. 213 * Ups should be ignored, and downs should be mapped to ups if 214 * that shift is currently on. 215 */ 216 if ((1 << (entry & 0x0F)) & 217 lower->kbtrans_keyboard->k_toggleshifts) { 218 if ((1 << (entry & 0x0F)) & lower->kbtrans_togglemask) { 219 newstate = KEY_RELEASED; /* toggling off */ 220 } else { 221 newstate = KEY_PRESSED; /* toggling on */ 222 } 223 } 224 } else { 225 /* 226 * Handle Compose and floating accent key sequences 227 */ 228 switch (lower->kbtrans_state) { 229 case COMPOSE1: 230 if (newstate == KEY_RELEASED) 231 return; 232 233 if (entry < ASCII_SET_SIZE) { 234 if (lower->kbtrans_compose_map[entry] >= 0) { 235 lower->kbtrans_compose_key = entry; 236 lower->kbtrans_state = COMPOSE2; 237 238 return; 239 } 240 } 241 lower->kbtrans_state = NORMAL; 242 lower->kbtrans_led_state &= ~LED_COMPOSE; 243 244 cb->kc_setled(lower->kbtrans_upper); 245 246 return; 247 248 case COMPOSE2: 249 if (newstate == KEY_RELEASED) 250 return; 251 252 /* next state is "normal" */ 253 lower->kbtrans_state = NORMAL; 254 lower->kbtrans_led_state &= ~LED_COMPOSE; 255 256 cb->kc_setled(lower->kbtrans_upper); 257 258 good_compose = kbtrans_do_compose(lower, 259 lower->kbtrans_compose_key, entry, &result); 260 if (good_compose) { 261 cb->kc_keypressed(lower->kbtrans_upper, 262 entrytype, key, result); 263 } 264 return; 265 266 case FLTACCENT: 267 if (newstate == KEY_RELEASED) 268 return; 269 270 /* next state is "normal" */ 271 lower->kbtrans_state = NORMAL; 272 for (i = 0; 273 (lower->kbtrans_fltaccent_table[i].fa_entry != 274 lower->kbtrans_fltaccent_entry) || 275 (lower->kbtrans_fltaccent_table[i].ascii != entry); 276 i++) { 277 if (lower->kbtrans_fltaccent_table[i].fa_entry 278 == 0) { 279 /* Invalid second key: ignore key */ 280 281 return; 282 } 283 } 284 285 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, 286 lower->kbtrans_fltaccent_table[i].utf8); 287 288 return; 289 } 290 } 291 292 /* 293 * If the key is going down, and it's not one of the keys that doesn't 294 * auto-repeat, set up the auto-repeat timeout. 295 * 296 * The keys that don't auto-repeat are the Compose key, 297 * the shift keys, the "bucky bit" keys, the "floating accent" keys, 298 * and the function keys when in TR_EVENT mode. 299 */ 300 if (newstate == KEY_PRESSED && entrytype != SHIFTKEYS && 301 entrytype != BUCKYBITS && entrytype != FUNNY && 302 entrytype != FA_CLASS) { 303 304 if (lower->kbtrans_repeatkey != key) { 305 cb->kc_cancel_repeat(lower->kbtrans_upper); 306 cb->kc_setup_repeat(lower->kbtrans_upper, entrytype, 307 key); 308 } 309 /* key going up */ 310 } else if (key == lower->kbtrans_repeatkey) { 311 312 cb->kc_cancel_repeat(lower->kbtrans_upper); 313 } 314 315 if (newstate == KEY_RELEASED) { 316 cb->kc_keyreleased(lower->kbtrans_upper, key); 317 } 318 319 /* 320 * We assume here that keys other than shift keys and bucky keys have 321 * entries in the "up" table that cause nothing to be done, and thus we 322 * don't have to check for newstate == KEY_RELEASED. 323 */ 324 switch (entrytype) { 325 326 case 0x0: /* regular key */ 327 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, 328 SPECIAL(lower->kbtrans_buckybits, entry)); 329 break; 330 331 case SHIFTKEYS: { 332 uint_t shiftbit = 1 << (entry & 0x0F); 333 334 /* Modify toggle state (see toggle processing above) */ 335 if (shiftbit & lower->kbtrans_keyboard->k_toggleshifts) { 336 if (newstate == KEY_RELEASED) { 337 if (shiftbit == CAPSMASK) { 338 lower->kbtrans_led_state &= 339 ~LED_CAPS_LOCK; 340 341 cb->kc_setled(lower->kbtrans_upper); 342 343 } else if (shiftbit == NUMLOCKMASK) { 344 lower->kbtrans_led_state &= 345 ~LED_NUM_LOCK; 346 347 cb->kc_setled(lower->kbtrans_upper); 348 } 349 lower->kbtrans_togglemask &= ~shiftbit; 350 } else { 351 if (shiftbit == CAPSMASK) { 352 lower->kbtrans_led_state |= 353 LED_CAPS_LOCK; 354 355 cb->kc_setled(lower->kbtrans_upper); 356 } else if (shiftbit == NUMLOCKMASK) { 357 lower->kbtrans_led_state |= 358 LED_NUM_LOCK; 359 360 cb->kc_setled(lower->kbtrans_upper); 361 } 362 lower->kbtrans_togglemask |= shiftbit; 363 } 364 } 365 366 if (newstate == KEY_RELEASED) 367 lower->kbtrans_shiftmask &= ~shiftbit; 368 else 369 lower->kbtrans_shiftmask |= shiftbit; 370 371 if (newstate == KEY_PRESSED) { 372 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, 373 entry); 374 } 375 376 break; 377 } 378 379 case BUCKYBITS: 380 lower->kbtrans_buckybits ^= 1 << (entry & 0x0F); 381 382 if (newstate == KEY_PRESSED) { 383 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, 384 entry); 385 } 386 387 break; 388 389 case FUNNY: 390 switch (entry) { 391 case NOP: 392 break; 393 394 case IDLE: 395 /* Fall thru into RESET code */ 396 /* FALLTHRU */ 397 case RESET: 398 case ERROR: 399 lower->kbtrans_shiftmask &= 400 lower->kbtrans_keyboard->k_idleshifts; 401 402 lower->kbtrans_shiftmask |= 403 lower->kbtrans_togglemask; 404 405 lower->kbtrans_buckybits &= 406 lower->kbtrans_keyboard->k_idlebuckys; 407 408 cb->kc_cancel_repeat(lower->kbtrans_upper); 409 410 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, 411 entry); 412 413 break; 414 415 416 case COMPOSE: 417 lower->kbtrans_state = COMPOSE1; 418 lower->kbtrans_led_state |= LED_COMPOSE; 419 cb->kc_setled(lower->kbtrans_upper); 420 break; 421 /* 422 * Remember when adding new entries that, 423 * if they should NOT auto-repeat, 424 * they should be put into the IF statement 425 * just above this switch block. 426 */ 427 default: 428 /* Ignore it */ 429 break; 430 } 431 break; 432 433 case FA_CLASS: 434 if (lower->kbtrans_state == NORMAL) { 435 lower->kbtrans_fltaccent_entry = entry; 436 lower->kbtrans_state = FLTACCENT; 437 } 438 break; 439 440 case STRING: 441 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry); 442 443 break; 444 445 case FUNCKEYS: 446 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry); 447 448 break; 449 450 /* 451 * Remember when adding new entries that, 452 * if they should NOT auto-repeat, 453 * they should be put into the IF statement 454 * just above this switch block. 455 */ 456 case PADKEYS: 457 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry); 458 459 break; 460 } 461 } 462 463 /* 464 * kbtrans_do_compose: 465 * Given a two key compose sequence, lookup the iso equivalent and put 466 * the result in the result_ptr. 467 */ 468 static boolean_t 469 kbtrans_do_compose(struct kbtrans_lower *lower, keymap_entry_t first_entry, 470 keymap_entry_t second_entry, keymap_entry_t *result_ptr) 471 { 472 struct compose_sequence_t *ptr; 473 keymap_entry_t tmp; 474 475 /* 476 * Validate the second keystroke. 477 */ 478 if (second_entry >= ASCII_SET_SIZE) 479 return (B_FALSE); 480 481 if (lower->kbtrans_compose_map[second_entry] < 0) 482 return (B_FALSE); 483 484 /* 485 * Get them in code order, rather than press order. 486 */ 487 if (first_entry > second_entry) { 488 tmp = first_entry; 489 first_entry = second_entry; 490 second_entry = tmp; 491 } 492 493 ptr = lower->kbtrans_compose_table + 494 lower->kbtrans_compose_map[first_entry]; 495 496 while (ptr->first == first_entry) { 497 if (ptr->second == second_entry) { 498 *result_ptr = ptr->utf8; 499 500 return (B_TRUE); 501 } 502 ptr++; 503 } 504 return (B_FALSE); 505 } 506 507 508 /* 509 * kbtrans_find_entry: 510 * This routine finds the entry corresponding to the current shift 511 * state and keycode. 512 */ 513 keymap_entry_t * 514 kbtrans_find_entry(struct kbtrans_lower *lower, uint_t mask, 515 kbtrans_key_t key_station) 516 { 517 register struct keyboard *kp; 518 keymap_entry_t *km; 519 struct exception_map *ex; 520 521 kp = lower->kbtrans_keyboard; 522 523 if (kp == NULL) 524 return (NULL); 525 526 if (key_station < 0 || key_station >= kp->k_keymap_size) 527 return (NULL); 528 529 ex = kp->k_except; 530 if (ex != NULL) { 531 for (; ex->exc_care != 0; ex++) { 532 if ((mask & ex->exc_care) == ex->exc_mask && 533 key_station == ex->exc_key) 534 return (&ex->exc_entry); 535 } 536 } 537 538 if (mask & UPMASK) 539 km = kp->k_up; 540 else if (mask & NUMLOCKMASK) 541 km = kp->k_numlock; 542 else if (mask & CTRLMASK) 543 km = kp->k_control; 544 else if (mask & ALTGRAPHMASK) 545 km = kp->k_altgraph; 546 else if (mask & SHIFTMASK) 547 km = kp->k_shifted; 548 else if (mask & CAPSMASK) 549 km = kp->k_caps; 550 else km = kp->k_normal; 551 552 return (&km[key_station]); 553 } 554 555 #ifdef DEBUG 556 /*ARGSUSED*/ 557 void 558 kbtrans_dprintf(void *un, const char *fmt, ...) 559 { 560 char buf[256]; 561 va_list ap; 562 563 va_start(ap, fmt); 564 (void) vsprintf(buf, fmt, ap); 565 va_end(ap); 566 567 cmn_err(CE_CONT, "kbtrans: %s", buf); 568 } 569 #endif 570