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