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