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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Generic keyboard support:  streams and administration.
  29  */
  30 
  31 #define KEYMAP_SIZE_VARIABLE
  32 
  33 #include <sys/types.h>
  34 #include <sys/cred.h>
  35 #include <sys/stream.h>
  36 #include <sys/stropts.h>
  37 #include <sys/strsun.h>
  38 #include <sys/ddi.h>
  39 #include <sys/vuid_event.h>
  40 #include <sys/modctl.h>
  41 #include <sys/errno.h>
  42 #include <sys/kmem.h>
  43 #include <sys/cmn_err.h>
  44 #include <sys/kbd.h>
  45 #include <sys/kbio.h>
  46 #include <sys/consdev.h>
  47 #include <sys/kbtrans.h>
  48 #include <sys/policy.h>
  49 #include <sys/sunldi.h>
  50 #include <sys/class.h>
  51 #include <sys/spl.h>
  52 #include "kbtrans_lower.h"
  53 #include "kbtrans_streams.h"
  54 
  55 #ifdef DEBUG
  56 int     kbtrans_errmask;
  57 int     kbtrans_errlevel;
  58 #endif
  59 
  60 #define KB_NR_FUNCKEYS          12
  61 
  62 /*
  63  * Repeat rates set in static variables so they can be tweeked with
  64  * debugger.
  65  */
  66 static int kbtrans_repeat_rate;
  67 static int kbtrans_repeat_delay;
  68 
  69 /* Printing message on q overflow */
  70 static int kbtrans_overflow_msg = 1;
  71 
  72 /*
  73  * This value corresponds approximately to max 10 fingers
  74  */
  75 static int      kbtrans_downs_size = 15;
  76 
  77 /*
  78  * modload support
  79  */
  80 extern struct mod_ops mod_miscops;
  81 
  82 static struct modlmisc modlmisc = {
  83         &mod_miscops,       /* Type of module */
  84         "kbtrans (key translation)"
  85 };
  86 
  87 static struct modlinkage modlinkage = {
  88         MODREV_1, (void *)&modlmisc, NULL
  89 };
  90 
  91 int
  92 _init(void)
  93 {
  94         return (mod_install(&modlinkage));
  95 }
  96 
  97 int
  98 _fini(void)
  99 {
 100         return (mod_remove(&modlinkage));
 101 }
 102 
 103 int
 104 _info(struct modinfo *modinfop)
 105 {
 106         return (mod_info(&modlinkage, modinfop));
 107 }
 108 
 109 /*
 110  * Internal Function Prototypes
 111  */
 112 static char     *kbtrans_strsetwithdecimal(char *, uint_t, uint_t);
 113 static void     kbtrans_set_translation_callback(struct kbtrans *);
 114 static void     kbtrans_reioctl(void *);
 115 static void     kbtrans_send_esc_event(char, struct kbtrans *);
 116 static void     kbtrans_keypressed(struct kbtrans *, uchar_t, Firm_event *,
 117                         ushort_t);
 118 static void     kbtrans_putbuf(char *, queue_t *);
 119 static void     kbtrans_cancelrpt(struct kbtrans *);
 120 static void     kbtrans_queuepress(struct kbtrans *, uchar_t, Firm_event *);
 121 static void     kbtrans_putcode(register struct kbtrans *, uint_t);
 122 static void     kbtrans_keyreleased(struct kbtrans *, uchar_t);
 123 static void     kbtrans_queueevent(struct kbtrans *, Firm_event *);
 124 static void     kbtrans_untrans_keypressed_raw(struct kbtrans *, kbtrans_key_t);
 125 static void     kbtrans_untrans_keyreleased_raw(struct kbtrans *,
 126                             kbtrans_key_t);
 127 static void     kbtrans_ascii_keypressed(struct kbtrans *, uint_t,
 128                         kbtrans_key_t, uint_t);
 129 static void     kbtrans_ascii_keyreleased(struct kbtrans *, kbtrans_key_t);
 130 static void     kbtrans_ascii_setup_repeat(struct kbtrans *, uint_t,
 131                         kbtrans_key_t);
 132 static void     kbtrans_trans_event_keypressed(struct kbtrans *, uint_t,
 133                         kbtrans_key_t, uint_t);
 134 static void     kbtrans_trans_event_keyreleased(struct kbtrans *,
 135                         kbtrans_key_t);
 136 static void     kbtrans_trans_event_setup_repeat(struct kbtrans *, uint_t,
 137                         kbtrans_key_t);
 138 static void     kbtrans_rpt(void *);
 139 static void     kbtrans_setled(struct kbtrans *);
 140 static void     kbtrans_flush(struct kbtrans *);
 141 static enum kbtrans_message_response    kbtrans_ioctl(struct kbtrans *upper,
 142                                                 mblk_t *mp);
 143 static int      kbtrans_setkey(struct kbtrans_lower *, struct kiockey *,
 144                         cred_t *);
 145 static int      kbtrans_getkey(struct kbtrans_lower *, struct kiockey *);
 146 static int      kbtrans_skey(struct kbtrans_lower *, struct kiockeymap *,
 147                                 cred_t *cr);
 148 static int      kbtrans_gkey(struct kbtrans_lower *, struct kiockeymap *);
 149 
 150 /*
 151  * Keyboard Translation Mode (TR_NONE)
 152  *
 153  * Functions to be called when keyboard translation is turned off
 154  * and up/down key codes are reported.
 155  */
 156 struct keyboard_callback        untrans_event_callback  = {
 157         kbtrans_untrans_keypressed_raw,
 158         kbtrans_untrans_keyreleased_raw,
 159         NULL,
 160         NULL,
 161         NULL,
 162         NULL,
 163         NULL,
 164 };
 165 
 166 /*
 167  * Keyboard Translation Mode (TR_ASCII)
 168  *
 169  * Functions to be called when ISO 8859/1 codes are reported
 170  */
 171 struct keyboard_callback        ascii_callback  = {
 172         NULL,
 173         NULL,
 174         kbtrans_ascii_keypressed,
 175         kbtrans_ascii_keyreleased,
 176         kbtrans_ascii_setup_repeat,
 177         kbtrans_cancelrpt,
 178         kbtrans_setled,
 179 };
 180 
 181 /*
 182  * Keyboard Translation Mode (TR_EVENT)
 183  *
 184  * Functions to be called when firm_events are reported.
 185  */
 186 struct keyboard_callback        trans_event_callback  = {
 187         NULL,
 188         NULL,
 189         kbtrans_trans_event_keypressed,
 190         kbtrans_trans_event_keyreleased,
 191         kbtrans_trans_event_setup_repeat,
 192         kbtrans_cancelrpt,
 193         kbtrans_setled,
 194 };
 195 
 196 static void
 197 progressbar_key_abort_thread(struct kbtrans *upper)
 198 {
 199         ldi_ident_t li;
 200         extern void progressbar_key_abort(ldi_ident_t);
 201 
 202         if (ldi_ident_from_stream(upper->kbtrans_streams_readq, &li) != 0) {
 203                 cmn_err(CE_NOTE, "!ldi_ident_from_stream failed");
 204         } else {
 205                 mutex_enter(&upper->progressbar_key_abort_lock);
 206                 while (upper->progressbar_key_abort_flag == 0)
 207                         cv_wait(&upper->progressbar_key_abort_cv,
 208                             &upper->progressbar_key_abort_lock);
 209                 if (upper->progressbar_key_abort_flag == 1) {
 210                         mutex_exit(&upper->progressbar_key_abort_lock);
 211                         progressbar_key_abort(li);
 212                 } else {
 213                         mutex_exit(&upper->progressbar_key_abort_lock);
 214                 }
 215                 ldi_ident_release(li);
 216         }
 217 
 218         thread_exit();
 219 }
 220 
 221 /*
 222  * kbtrans_streams_init:
 223  *      Initialize the stream, keytables, callbacks, etc.
 224  */
 225 int
 226 kbtrans_streams_init(
 227         queue_t                         *q,
 228         int                             sflag,
 229         struct kbtrans_hardware         *hw,
 230         struct kbtrans_callbacks        *hw_cb,
 231         struct kbtrans                  **ret_kbd,
 232         int                             initial_leds,
 233         int                             initial_led_mask)
 234 {
 235         struct kbtrans *upper;
 236         struct kbtrans_lower *lower;
 237         kthread_t *tid;
 238 
 239         /*
 240          * Default to relatively generic tables.
 241          */
 242         extern signed char                      kb_compose_map[];
 243         extern struct compose_sequence_t        kb_compose_table[];
 244         extern struct fltaccent_sequence_t      kb_fltaccent_table[];
 245         extern char                             keystringtab[][KTAB_STRLEN];
 246         extern unsigned char                    kb_numlock_table[];
 247 
 248         /* Set these up only once so that they could be changed from adb */
 249         if (!kbtrans_repeat_rate) {
 250                 kbtrans_repeat_rate = (hz+29)/30;
 251                 kbtrans_repeat_delay = hz/2;
 252         }
 253 
 254         switch (sflag) {
 255 
 256         case MODOPEN:
 257                 break;
 258 
 259         case CLONEOPEN:
 260                 DPRINTF(PRINT_L1, PRINT_MASK_OPEN, (NULL,
 261                     "kbtrans_streams_init: Clone open not supported"));
 262 
 263                 return (EINVAL);
 264         }
 265 
 266         /* allocate keyboard state structure */
 267         upper = kmem_zalloc(sizeof (struct kbtrans), KM_SLEEP);
 268 
 269         *ret_kbd = upper;
 270 
 271         upper->kbtrans_polled_buf[0] = '\0';
 272         upper->kbtrans_polled_pending_chars = upper->kbtrans_polled_buf;
 273 
 274         upper->kbtrans_streams_hw = hw;
 275         upper->kbtrans_streams_hw_callbacks = hw_cb;
 276         upper->kbtrans_streams_readq = q;
 277         upper->kbtrans_streams_iocpending = NULL;
 278         upper->kbtrans_streams_translatable = TR_CAN;
 279         upper->kbtrans_overflow_cnt = 0;
 280         upper->kbtrans_streams_translate_mode = TR_ASCII;
 281 
 282         /* Set the translation callback based on the translation type */
 283         kbtrans_set_translation_callback(upper);
 284 
 285         lower = &upper->kbtrans_lower;
 286 
 287         /*
 288          * Set defaults for relatively generic tables.
 289          */
 290         lower->kbtrans_compose_map = kb_compose_map;
 291         lower->kbtrans_compose_table = kb_compose_table;
 292         lower->kbtrans_fltaccent_table = kb_fltaccent_table;
 293         lower->kbtrans_numlock_table = kb_numlock_table;
 294         lower->kbtrans_keystringtab = keystringtab;
 295 
 296         lower->kbtrans_upper = upper;
 297         lower->kbtrans_compat = 1;
 298 
 299         /*
 300          * We have a generic default for the LED state, and let the
 301          * hardware-specific driver supply overrides.
 302          */
 303         lower->kbtrans_led_state = 0;
 304         lower->kbtrans_led_state &= ~initial_led_mask;
 305         lower->kbtrans_led_state |= initial_leds;
 306         lower->kbtrans_togglemask = 0;
 307 
 308         if (lower->kbtrans_led_state & LED_CAPS_LOCK)
 309                 lower->kbtrans_togglemask |= CAPSMASK;
 310         if (lower->kbtrans_led_state & LED_NUM_LOCK)
 311                 lower->kbtrans_togglemask |= NUMLOCKMASK;
 312 
 313 #if     defined(SCROLLMASK)
 314         if (lower->kbtrans_led_state & LED_SCROLL_LOCK)
 315                 lower->kbtrans_togglemask |= SCROLLMASK;
 316 #endif
 317 
 318         lower->kbtrans_shiftmask = lower->kbtrans_togglemask;
 319 
 320         upper->kbtrans_streams_vuid_addr.ascii = ASCII_FIRST;
 321         upper->kbtrans_streams_vuid_addr.top = TOP_FIRST;
 322         upper->kbtrans_streams_vuid_addr.vkey = VKEY_FIRST;
 323 
 324         /* Allocate dynamic memory for downs table */
 325         upper->kbtrans_streams_num_downs_entries = kbtrans_downs_size;
 326         upper->kbtrans_streams_downs_bytes =
 327             (uint32_t)(kbtrans_downs_size * sizeof (Key_event));
 328         upper->kbtrans_streams_downs =
 329             kmem_zalloc(upper->kbtrans_streams_downs_bytes, KM_SLEEP);
 330         upper->kbtrans_streams_abortable = B_FALSE;
 331 
 332         upper->kbtrans_streams_flags = KBTRANS_STREAMS_OPEN;
 333 
 334         upper->progressbar_key_abort_flag = 0;
 335         cv_init(&upper->progressbar_key_abort_cv, NULL, CV_DEFAULT, NULL);
 336         /* this counts on no keyboards being above ipl 12 */
 337         mutex_init(&upper->progressbar_key_abort_lock, NULL, MUTEX_SPIN,
 338             (void *)ipltospl(12));
 339         tid = thread_create(NULL, 0, progressbar_key_abort_thread, upper,
 340             0, &p0, TS_RUN, minclsyspri);
 341         upper->progressbar_key_abort_t_did = tid->t_did;
 342 
 343         DPRINTF(PRINT_L1, PRINT_MASK_OPEN, (upper, "kbtrans_streams_init "
 344             "exiting"));
 345         return (0);
 346 }
 347 
 348 
 349 /*
 350  * kbtrans_streams_fini:
 351  *      Free structures and uninitialize the stream
 352  */
 353 int
 354 kbtrans_streams_fini(struct kbtrans *upper)
 355 {
 356         /*
 357          * Since we're about to destroy our private data, turn off
 358          * our open flag first, so we don't accept any more input
 359          * and try to use that data.
 360          */
 361         upper->kbtrans_streams_flags = 0;
 362 
 363         /* clear all timeouts */
 364         if (upper->kbtrans_streams_bufcallid) {
 365                 qunbufcall(upper->kbtrans_streams_readq,
 366                     upper->kbtrans_streams_bufcallid);
 367         }
 368         if (upper->kbtrans_streams_rptid) {
 369                 (void) quntimeout(upper->kbtrans_streams_readq,
 370                     upper->kbtrans_streams_rptid);
 371         }
 372         kmem_free(upper->kbtrans_streams_downs,
 373             upper->kbtrans_streams_downs_bytes);
 374 
 375         mutex_enter(&upper->progressbar_key_abort_lock);
 376         if (upper->progressbar_key_abort_flag == 0) {
 377                 upper->progressbar_key_abort_flag = 2;
 378                 cv_signal(&upper->progressbar_key_abort_cv);
 379                 mutex_exit(&upper->progressbar_key_abort_lock);
 380                 thread_join(upper->progressbar_key_abort_t_did);
 381         } else {
 382                 mutex_exit(&upper->progressbar_key_abort_lock);
 383         }
 384         cv_destroy(&upper->progressbar_key_abort_cv);
 385         mutex_destroy(&upper->progressbar_key_abort_lock);
 386 
 387         kmem_free(upper, sizeof (struct kbtrans));
 388 
 389         DPRINTF(PRINT_L1, PRINT_MASK_CLOSE, (upper, "kbtrans_streams_fini "
 390             "exiting"));
 391         return (0);
 392 }
 393 
 394 /*
 395  * kbtrans_streams_releaseall :
 396  *      This function releases all the held keys.
 397  */
 398 void
 399 kbtrans_streams_releaseall(struct kbtrans *upper)
 400 {
 401         register struct key_event *ke;
 402         register int i;
 403 
 404         DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL, "USBKBM RELEASE ALL\n"));
 405 
 406         /* Scan table of down key stations */
 407         for (i = 0, ke = upper->kbtrans_streams_downs;
 408             i < upper->kbtrans_streams_num_downs_entries; i++, ke++) {
 409 
 410                 /* Key station not zero */
 411                 if (ke->key_station) {
 412 
 413                         kbtrans_keyreleased(upper, ke->key_station);
 414                         /* kbtrans_keyreleased resets downs entry */
 415                 }
 416         }
 417 }
 418 
 419 /*
 420  * kbtrans_streams_message:
 421  *      keyboard module output queue put procedure: handles M_IOCTL
 422  *      messages.
 423  *
 424  *      Return KBTRANS_MESSAGE_HANDLED if the message was handled by
 425  *      kbtrans and KBTRANS_MESSAGE_NOT_HANDLED otherwise. If
 426  *      KBTRANS_MESSAGE_HANDLED is returned, no further action is required.
 427  *      If KBTRANS_MESSAGE_NOT_HANDLED is returned, the hardware module
 428  *      is responsible for any action.
 429  */
 430 enum kbtrans_message_response
 431 kbtrans_streams_message(struct kbtrans *upper, register mblk_t *mp)
 432 {
 433         queue_t *q = upper->kbtrans_streams_readq;
 434         enum kbtrans_message_response ret;
 435 
 436         DPRINTF(PRINT_L1, PRINT_MASK_ALL, (upper,
 437             "kbtrans_streams_message entering"));
 438         /*
 439          * Process M_FLUSH, and some M_IOCTL, messages here; pass
 440          * everything else down.
 441          */
 442         switch (mp->b_datap->db_type) {
 443 
 444         case M_IOCTL:
 445                 ret = kbtrans_ioctl(upper, mp);
 446                 break;
 447 
 448         case M_FLUSH:
 449                 if (*mp->b_rptr & FLUSHW)
 450                         flushq(q, FLUSHDATA);
 451                 if (*mp->b_rptr & FLUSHR)
 452                         flushq(RD(q), FLUSHDATA);
 453                 /*
 454                  * White lie:  we say we didn't handle the message,
 455                  * so that it gets handled by our client.
 456                  */
 457                 ret = KBTRANS_MESSAGE_NOT_HANDLED;
 458                 break;
 459 
 460         default:
 461                 ret = KBTRANS_MESSAGE_NOT_HANDLED;
 462                 break;
 463 
 464         }
 465         DPRINTF(PRINT_L1, PRINT_MASK_ALL, (upper,
 466             "kbtrans_streams_message exiting\n"));
 467 
 468         return (ret);
 469 }
 470 
 471 /*
 472  * kbtrans_streams_key:
 473  *      When a key is pressed or released, the hardware module should
 474  *      call kbtrans, passing the key number and its new
 475  *      state.  kbtrans is responsible for autorepeat handling;
 476  *      the hardware module should report only actual press/release
 477  *      events, suppressing any hardware-generated autorepeat.
 478  */
 479 void
 480 kbtrans_streams_key(
 481     struct kbtrans *upper,
 482     kbtrans_key_t key,
 483     enum keystate state)
 484 {
 485         struct kbtrans_lower *lower;
 486         struct keyboard *kp;
 487 
 488         lower = &upper->kbtrans_lower;
 489         kp = lower->kbtrans_keyboard;
 490 
 491         /* trigger switch back to text mode */
 492         mutex_enter(&upper->progressbar_key_abort_lock);
 493         if (upper->progressbar_key_abort_flag == 0) {
 494                 upper->progressbar_key_abort_flag = 1;
 495                 cv_signal(&upper->progressbar_key_abort_cv);
 496         }
 497         mutex_exit(&upper->progressbar_key_abort_lock);
 498 
 499         if (upper->kbtrans_streams_abortable) {
 500                 switch (upper->kbtrans_streams_abort_state) {
 501                 case ABORT_NORMAL:
 502                         if (state != KEY_PRESSED)
 503                                 break;
 504 
 505                         if (key == (kbtrans_key_t)kp->k_abort1 ||
 506                             key == (kbtrans_key_t)kp->k_abort1a) {
 507                                 upper->kbtrans_streams_abort_state =
 508                                     ABORT_ABORT1_RECEIVED;
 509                                 upper->kbtrans_streams_abort1_key = key;
 510                                 return;
 511                         }
 512                         /* Shift key needs to be sent to upper immediately */
 513                         if (key == (kbtrans_key_t)kp->k_newabort1 ||
 514                             key == (kbtrans_key_t)kp->k_newabort1a) {
 515                                 upper->kbtrans_streams_abort_state =
 516                                     NEW_ABORT_ABORT1_RECEIVED;
 517                                 upper->kbtrans_streams_new_abort1_key = key;
 518                         }
 519                         break;
 520                 case ABORT_ABORT1_RECEIVED:
 521                         upper->kbtrans_streams_abort_state = ABORT_NORMAL;
 522                         if (state == KEY_PRESSED &&
 523                             key == (kbtrans_key_t)kp->k_abort2) {
 524                                 abort_sequence_enter((char *)NULL);
 525                                 return;
 526                         } else {
 527                                 kbtrans_processkey(lower,
 528                                     upper->kbtrans_streams_callback,
 529                                     upper->kbtrans_streams_abort1_key,
 530                                     KEY_PRESSED);
 531                         }
 532                         break;
 533                 case NEW_ABORT_ABORT1_RECEIVED:
 534                         upper->kbtrans_streams_abort_state = ABORT_NORMAL;
 535                         if (state == KEY_PRESSED &&
 536                             key == (kbtrans_key_t)kp->k_newabort2) {
 537                                 abort_sequence_enter((char *)NULL);
 538                                 kbtrans_processkey(lower,
 539                                     upper->kbtrans_streams_callback,
 540                                     upper->kbtrans_streams_new_abort1_key,
 541                                     KEY_RELEASED);
 542                                 return;
 543                         }
 544                 }
 545         }
 546 
 547         kbtrans_processkey(lower, upper->kbtrans_streams_callback, key, state);
 548 }
 549 
 550 /*
 551  * kbtrans_streams_set_keyboard:
 552  *      At any time after calling kbtrans_streams_init, the hardware
 553  *      module should make this call to report the id of the keyboard
 554  *      attached. id is the keyboard type, typically KB_SUN4,
 555  *      KB_PC, or KB_USB.
 556  */
 557 void
 558 kbtrans_streams_set_keyboard(
 559     struct kbtrans      *upper,
 560     int                 id,
 561     struct keyboard     *k)
 562 {
 563         upper->kbtrans_lower.kbtrans_keyboard = k;
 564         upper->kbtrans_streams_id = id;
 565 }
 566 
 567 /*
 568  * kbtrans_streams_has_reset:
 569  *      At any time between kbtrans_streams_init and kbtrans_streams_fini,
 570  *      the hardware module can call this routine to report that the
 571  *      keyboard has been reset, e.g. by being unplugged and reattached.
 572  */
 573 /*ARGSUSED*/
 574 void
 575 kbtrans_streams_has_reset(struct kbtrans *upper)
 576 {
 577         /*
 578          * If this routine is implemented it should probably (a)
 579          * simulate releases of all pressed keys and (b) call
 580          * the hardware module to set the LEDs.
 581          */
 582 }
 583 
 584 /*
 585  * kbtrans_streams_enable:
 586  *      This is the routine that is called back when the the stream is ready
 587  *      to take messages.
 588  */
 589 void
 590 kbtrans_streams_enable(struct kbtrans *upper)
 591 {
 592         /* Set the LED's */
 593         kbtrans_setled(upper);
 594 }
 595 
 596 /*
 597  * kbtrans_streams_setled():
 598  *      This is the routine that is called to only update the led state
 599  *      in kbtrans.
 600  */
 601 void
 602 kbtrans_streams_setled(struct kbtrans *upper, int led_state)
 603 {
 604         struct kbtrans_lower *lower;
 605 
 606         lower = &upper->kbtrans_lower;
 607         lower->kbtrans_led_state = (uchar_t)led_state;
 608 
 609         if (lower->kbtrans_led_state & LED_CAPS_LOCK)
 610                 lower->kbtrans_togglemask |= CAPSMASK;
 611         if (lower->kbtrans_led_state & LED_NUM_LOCK)
 612                 lower->kbtrans_togglemask |= NUMLOCKMASK;
 613 
 614 #if     defined(SCROLLMASK)
 615         if (lower->kbtrans_led_state & LED_SCROLL_LOCK)
 616                 lower->kbtrans_togglemask |= SCROLLMASK;
 617 #endif
 618 
 619         lower->kbtrans_shiftmask = lower->kbtrans_togglemask;
 620 
 621 }
 622 
 623 /*
 624  * kbtrans_streams_set_queue:
 625  *      Set the overlying queue, to support multiplexors.
 626  */
 627 void
 628 kbtrans_streams_set_queue(struct kbtrans *upper, queue_t *q)
 629 {
 630 
 631         upper->kbtrans_streams_readq = q;
 632 }
 633 
 634 /*
 635  * kbtrans_streams_get_queue:
 636  *      Return the overlying queue.
 637  */
 638 queue_t *
 639 kbtrans_streams_get_queue(struct kbtrans *upper)
 640 {
 641         return (upper->kbtrans_streams_readq);
 642 }
 643 
 644 /*
 645  * kbtrans_streams_untimeout
 646  *      Cancell all timeout
 647  */
 648 void
 649 kbtrans_streams_untimeout(struct kbtrans *upper)
 650 {
 651         /* clear all timeouts */
 652         if (upper->kbtrans_streams_bufcallid) {
 653                 qunbufcall(upper->kbtrans_streams_readq,
 654                     upper->kbtrans_streams_bufcallid);
 655                 upper->kbtrans_streams_bufcallid = 0;
 656         }
 657         if (upper->kbtrans_streams_rptid) {
 658                 (void) quntimeout(upper->kbtrans_streams_readq,
 659                     upper->kbtrans_streams_rptid);
 660                 upper->kbtrans_streams_rptid = 0;
 661         }
 662 }
 663 
 664 /*
 665  * kbtrans_reioctl:
 666  *      This function is set up as call-back function should an ioctl fail
 667  *      to allocate required resources.
 668  */
 669 static void
 670 kbtrans_reioctl(void    *arg)
 671 {
 672         struct kbtrans *upper = (struct kbtrans *)arg;
 673         mblk_t *mp;
 674 
 675         upper->kbtrans_streams_bufcallid = 0;
 676 
 677         if ((mp = upper->kbtrans_streams_iocpending) != NULL) {
 678                 /* not pending any more */
 679                 upper->kbtrans_streams_iocpending = NULL;
 680                 (void) kbtrans_ioctl(upper, mp);
 681         }
 682 }
 683 
 684 /*
 685  * kbtrans_ioctl:
 686  *      process ioctls we recognize and own.  Otherwise, pass it down.
 687  */
 688 static enum kbtrans_message_response
 689 kbtrans_ioctl(struct kbtrans *upper, register mblk_t *mp)
 690 {
 691         register struct iocblk *iocp;
 692         register short  new_translate;
 693         register Vuid_addr_probe *addr_probe;
 694         register short  *addr_ptr;
 695         size_t  ioctlrespsize;
 696         int     err = 0;
 697         struct kbtrans_lower *lower;
 698         mblk_t *datap;
 699         int     translate;
 700 
 701         static int kiocgetkey, kiocsetkey;
 702 
 703         lower = &upper->kbtrans_lower;
 704 
 705         iocp = (struct iocblk *)mp->b_rptr;
 706 
 707         DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper,
 708             "kbtrans_ioctl: ioc_cmd 0x%x - ", iocp->ioc_cmd));
 709         switch (iocp->ioc_cmd) {
 710 
 711         case VUIDSFORMAT:
 712                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDSFORMAT\n"));
 713 
 714                 err = miocpullup(mp, sizeof (int));
 715                 if (err != 0)
 716                         break;
 717                 new_translate = (*(int *)mp->b_cont->b_rptr == VUID_NATIVE) ?
 718                     TR_ASCII : TR_EVENT;
 719 
 720                 if (new_translate == upper->kbtrans_streams_translate_mode)
 721                         break;
 722                 upper->kbtrans_streams_translate_mode = new_translate;
 723 
 724                 kbtrans_set_translation_callback(upper);
 725 
 726                 kbtrans_flush(upper);
 727                 break;
 728 
 729         case KIOCTRANS:
 730                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCTRANS\n"));
 731                 err = miocpullup(mp, sizeof (int));
 732                 if (err != 0)
 733                         break;
 734                 new_translate = *(int *)mp->b_cont->b_rptr;
 735                 if (new_translate == upper->kbtrans_streams_translate_mode)
 736                         break;
 737                 upper->kbtrans_streams_translate_mode = new_translate;
 738                 kbtrans_set_translation_callback(upper);
 739 
 740                 kbtrans_flush(upper);
 741                 break;
 742 
 743         case KIOCSLED:
 744                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSLED\n"));
 745 
 746                 err = miocpullup(mp, sizeof (uchar_t));
 747                 if (err != 0)
 748                         break;
 749                 lower->kbtrans_led_state = *(uchar_t *)mp->b_cont->b_rptr;
 750 
 751                 kbtrans_setled(upper);
 752                 break;
 753 
 754         case KIOCGLED:
 755                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGLED\n"));
 756                 if ((datap = allocb(sizeof (uchar_t), BPRI_HI)) == NULL) {
 757                         ioctlrespsize = sizeof (int);
 758                         goto allocfailure;
 759                 }
 760 
 761                 *(uchar_t *)datap->b_wptr = lower->kbtrans_led_state;
 762                 datap->b_wptr += sizeof (uchar_t);
 763                 if (mp->b_cont)
 764                         freemsg(mp->b_cont);
 765                 mp->b_cont = datap;
 766                 iocp->ioc_count = sizeof (uchar_t);
 767                 break;
 768 
 769         case VUIDGFORMAT:
 770                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDGFORMAT\n"));
 771                 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
 772                         ioctlrespsize = sizeof (int);
 773                         goto allocfailure;
 774                 }
 775                 *(int *)datap->b_wptr =
 776                     (upper->kbtrans_streams_translate_mode == TR_EVENT ||
 777                     upper->kbtrans_streams_translate_mode == TR_UNTRANS_EVENT) ?
 778                     VUID_FIRM_EVENT: VUID_NATIVE;
 779                 datap->b_wptr += sizeof (int);
 780                 if (mp->b_cont)  /* free msg to prevent memory leak */
 781                         freemsg(mp->b_cont);
 782                 mp->b_cont = datap;
 783                 iocp->ioc_count = sizeof (int);
 784                 break;
 785 
 786         case KIOCGTRANS:
 787                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGTRANS\n"));
 788                 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
 789                         ioctlrespsize = sizeof (int);
 790                         goto allocfailure;
 791                 }
 792                 *(int *)datap->b_wptr = upper->kbtrans_streams_translate_mode;
 793                 datap->b_wptr += sizeof (int);
 794                 if (mp->b_cont)  /* free msg to prevent memory leak */
 795                         freemsg(mp->b_cont);
 796                 mp->b_cont = datap;
 797                 iocp->ioc_count = sizeof (int);
 798                 break;
 799 
 800         case VUIDSADDR:
 801                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDSADDR\n"));
 802 
 803                 err = miocpullup(mp, sizeof (Vuid_addr_probe));
 804                 if (err != 0)
 805                         break;
 806                 addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
 807                 switch (addr_probe->base) {
 808 
 809                 case ASCII_FIRST:
 810                         addr_ptr = &upper->kbtrans_streams_vuid_addr.ascii;
 811                         break;
 812 
 813                 case TOP_FIRST:
 814                         addr_ptr = &upper->kbtrans_streams_vuid_addr.top;
 815                         break;
 816 
 817                 case VKEY_FIRST:
 818                         addr_ptr = &upper->kbtrans_streams_vuid_addr.vkey;
 819                         break;
 820 
 821                 default:
 822                         err = ENODEV;
 823                 }
 824 
 825                 if ((err == 0) && (*addr_ptr != addr_probe->data.next)) {
 826                         *addr_ptr = addr_probe->data.next;
 827                         kbtrans_flush(upper);
 828                 }
 829                 break;
 830 
 831         case VUIDGADDR:
 832                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDGADDR\n"));
 833 
 834                 err = miocpullup(mp, sizeof (Vuid_addr_probe));
 835                 if (err != 0)
 836                         break;
 837                 addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
 838                 switch (addr_probe->base) {
 839 
 840                 case ASCII_FIRST:
 841                         addr_probe->data.current =
 842                             upper->kbtrans_streams_vuid_addr.ascii;
 843                         break;
 844 
 845                 case TOP_FIRST:
 846                         addr_probe->data.current =
 847                             upper->kbtrans_streams_vuid_addr.top;
 848                         break;
 849 
 850                 case VKEY_FIRST:
 851                         addr_probe->data.current =
 852                             upper->kbtrans_streams_vuid_addr.vkey;
 853                         break;
 854 
 855                 default:
 856                         err = ENODEV;
 857                 }
 858                 break;
 859 
 860         case KIOCTRANSABLE:
 861                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCTRANSABLE\n"));
 862 
 863                 err = miocpullup(mp, sizeof (int));
 864                 if (err != 0)
 865                         break;
 866                 /*
 867                  * called during console setup in kbconfig()
 868                  * If set to false, means we are a serial keyboard,
 869                  * and we should pass all data up without modification.
 870                  */
 871                 translate = *(int *)mp->b_cont->b_rptr;
 872                 if (upper->kbtrans_streams_translatable != translate)
 873                         upper->kbtrans_streams_translatable = translate;
 874 
 875                 if (translate != TR_CAN)
 876                         DPRINTF(PRINT_L4, PRINT_MASK_ALL, (upper,
 877                             "Cannot translate keyboard using tables.\n"));
 878                 break;
 879 
 880         case KIOCGTRANSABLE:
 881                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGTRANSABLE\n"));
 882                 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
 883                         ioctlrespsize = sizeof (int);
 884                         goto allocfailure;
 885                 }
 886                 *(int *)datap->b_wptr = upper->kbtrans_streams_translatable;
 887                 datap->b_wptr += sizeof (int);
 888                 if (mp->b_cont)  /* free msg to prevent memory leak */
 889                         freemsg(mp->b_cont);
 890                 mp->b_cont = datap;
 891                 iocp->ioc_count = sizeof (int);
 892                 break;
 893 
 894         case KIOCSCOMPAT:
 895                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSCOMPAT\n"));
 896 
 897                 err = miocpullup(mp, sizeof (int));
 898                 if (err != 0)
 899                         break;
 900                 lower->kbtrans_compat = *(int *)mp->b_cont->b_rptr;
 901                 break;
 902 
 903         case KIOCGCOMPAT:
 904                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGCOMPAT\n"));
 905                 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
 906                         ioctlrespsize = sizeof (int);
 907                         goto allocfailure;
 908                 }
 909                 *(int *)datap->b_wptr = lower->kbtrans_compat;
 910                 datap->b_wptr += sizeof (int);
 911                 if (mp->b_cont)  /* free msg to prevent memory leak */
 912                         freemsg(mp->b_cont);
 913                 mp->b_cont = datap;
 914                 iocp->ioc_count = sizeof (int);
 915                 break;
 916 
 917         case KIOCSETKEY:
 918                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSETKEY %d\n",
 919                     kiocsetkey++));
 920                 err = miocpullup(mp, sizeof (struct kiockey));
 921                 if (err != 0)
 922                         break;
 923                 err = kbtrans_setkey(&upper->kbtrans_lower,
 924                     (struct kiockey *)mp->b_cont->b_rptr, iocp->ioc_cr);
 925                 /*
 926                  * Since this only affects any subsequent key presses,
 927                  * don't flush soft state.  One might want to
 928                  * toggle the keytable entries dynamically.
 929                  */
 930                 break;
 931 
 932         case KIOCGETKEY:
 933                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGETKEY %d\n",
 934                     kiocgetkey++));
 935                 err = miocpullup(mp, sizeof (struct kiockey));
 936                 if (err != 0)
 937                         break;
 938                 err = kbtrans_getkey(&upper->kbtrans_lower,
 939                     (struct kiockey *)mp->b_cont->b_rptr);
 940                 break;
 941 
 942         case KIOCSKEY:
 943                 err = miocpullup(mp, sizeof (struct kiockeymap));
 944                 if (err != 0)
 945                         break;
 946                 err = kbtrans_skey(&upper->kbtrans_lower,
 947                     (struct kiockeymap *)mp->b_cont->b_rptr, iocp->ioc_cr);
 948                 /*
 949                  * Since this only affects any subsequent key presses,
 950                  * don't flush soft state.  One might want to
 951                  * toggle the keytable entries dynamically.
 952                  */
 953                 break;
 954 
 955         case KIOCGKEY:
 956                 err = miocpullup(mp, sizeof (struct kiockeymap));
 957                 if (err != 0)
 958                         break;
 959                 err = kbtrans_gkey(&upper->kbtrans_lower,
 960                     (struct kiockeymap *)mp->b_cont->b_rptr);
 961                 break;
 962 
 963         case KIOCSDIRECT:
 964                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSDIRECT\n"));
 965                 kbtrans_flush(upper);
 966                 break;
 967 
 968         case KIOCGDIRECT:
 969                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSGDIRECT\n"));
 970                 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
 971                         ioctlrespsize = sizeof (int);
 972                         goto allocfailure;
 973                 }
 974                 *(int *)datap->b_wptr = 1;   /* always direct */
 975                 datap->b_wptr += sizeof (int);
 976                 if (mp->b_cont) /* free msg to prevent memory leak */
 977                         freemsg(mp->b_cont);
 978                 mp->b_cont = datap;
 979                 iocp->ioc_count = sizeof (int);
 980                 break;
 981 
 982         case KIOCTYPE:
 983                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCTYPE\n"));
 984                 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
 985                         ioctlrespsize = sizeof (int);
 986                         goto allocfailure;
 987                 }
 988                 *(int *)datap->b_wptr = upper->kbtrans_streams_id;
 989                 datap->b_wptr += sizeof (int);
 990                 if (mp->b_cont) /* free msg to prevent memory leak */
 991                         freemsg(mp->b_cont);
 992                 mp->b_cont = datap;
 993                 iocp->ioc_count = sizeof (int);
 994                 break;
 995 
 996         case CONSSETABORTENABLE:
 997                 /*
 998                  * Peek as it goes by; must be a TRANSPARENT ioctl.
 999                  */
1000                 if (iocp->ioc_count != TRANSPARENT) {
1001                         err = EINVAL;
1002                         break;
1003                 }
1004 
1005                 upper->kbtrans_streams_abortable =
1006                     (boolean_t)*(intptr_t *)mp->b_cont->b_rptr;
1007 
1008                 /*
1009                  * Let the hardware module see it too.
1010                  */
1011                 return (KBTRANS_MESSAGE_NOT_HANDLED);
1012 
1013         case KIOCGRPTDELAY:
1014                 /*
1015                  * Report the autorepeat delay, unit in millisecond
1016                  */
1017                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGRPTDELAY\n"));
1018                 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1019                         ioctlrespsize = sizeof (int);
1020                         goto allocfailure;
1021                 }
1022                 *(int *)datap->b_wptr = TICK_TO_MSEC(kbtrans_repeat_delay);
1023                 datap->b_wptr += sizeof (int);
1024 
1025                 /* free msg to prevent memory leak */
1026                 if (mp->b_cont != NULL)
1027                         freemsg(mp->b_cont);
1028                 mp->b_cont = datap;
1029                 iocp->ioc_count = sizeof (int);
1030                 break;
1031 
1032         case KIOCSRPTDELAY:
1033                 /*
1034                  * Set the autorepeat delay
1035                  */
1036                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSRPTDELAY\n"));
1037                 err = miocpullup(mp, sizeof (int));
1038 
1039                 if (err != 0)
1040                         break;
1041 
1042                 /* validate the input */
1043                 if (*(int *)mp->b_cont->b_rptr < KIOCRPTDELAY_MIN) {
1044                         err = EINVAL;
1045                         break;
1046                 }
1047                 kbtrans_repeat_delay = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
1048                 if (kbtrans_repeat_delay <= 0)
1049                         kbtrans_repeat_delay = 1;
1050                 break;
1051 
1052         case KIOCGRPTRATE:
1053                 /*
1054                  * Report the autorepeat rate
1055                  */
1056                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGRPTRATE\n"));
1057                 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1058                         ioctlrespsize = sizeof (int);
1059                         goto allocfailure;
1060                 }
1061                 *(int *)datap->b_wptr = TICK_TO_MSEC(kbtrans_repeat_rate);
1062                 datap->b_wptr += sizeof (int);
1063 
1064                 /* free msg to prevent memory leak */
1065                 if (mp->b_cont != NULL)
1066                         freemsg(mp->b_cont);
1067                 mp->b_cont = datap;
1068                 iocp->ioc_count = sizeof (int);
1069                 break;
1070 
1071         case KIOCSRPTRATE:
1072                 /*
1073                  * Set the autorepeat rate
1074                  */
1075                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSRPTRATE\n"));
1076                 err = miocpullup(mp, sizeof (int));
1077 
1078                 if (err != 0)
1079                         break;
1080 
1081                 /* validate the input */
1082                 if (*(int *)mp->b_cont->b_rptr < KIOCRPTRATE_MIN) {
1083                         err = EINVAL;
1084                         break;
1085                 }
1086                 kbtrans_repeat_rate = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
1087                 if (kbtrans_repeat_rate <= 0)
1088                         kbtrans_repeat_rate = 1;
1089                 break;
1090 
1091         default:
1092                 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "unknown\n"));
1093                 return (KBTRANS_MESSAGE_NOT_HANDLED);
1094         } /* end switch */
1095 
1096         if (err != 0) {
1097                 iocp->ioc_rval = 0;
1098                 iocp->ioc_error = err;
1099                 mp->b_datap->db_type = M_IOCNAK;
1100         } else {
1101                 iocp->ioc_rval = 0;
1102                 iocp->ioc_error = 0; /* brain rot */
1103                 mp->b_datap->db_type = M_IOCACK;
1104         }
1105         putnext(upper->kbtrans_streams_readq, mp);
1106 
1107         return (KBTRANS_MESSAGE_HANDLED);
1108 
1109 allocfailure:
1110         /*
1111          * We needed to allocate something to handle this "ioctl", but
1112          * couldn't; save this "ioctl" and arrange to get called back when
1113          * it's more likely that we can get what we need.
1114          * If there's already one being saved, throw it out, since it
1115          * must have timed out.
1116          */
1117         if (upper->kbtrans_streams_iocpending != NULL)
1118                 freemsg(upper->kbtrans_streams_iocpending);
1119         upper->kbtrans_streams_iocpending = mp;
1120         if (upper->kbtrans_streams_bufcallid) {
1121                 qunbufcall(upper->kbtrans_streams_readq,
1122                     upper->kbtrans_streams_bufcallid);
1123         }
1124         upper->kbtrans_streams_bufcallid =
1125             qbufcall(upper->kbtrans_streams_readq, ioctlrespsize, BPRI_HI,
1126             kbtrans_reioctl, upper);
1127         /*
1128          * This is a white lie... we *will* handle it, eventually.
1129          */
1130         return (KBTRANS_MESSAGE_HANDLED);
1131 }
1132 
1133 /*
1134  * kbtrans_flush:
1135  *      Flush data upstream
1136  */
1137 static void
1138 kbtrans_flush(register struct kbtrans *upper)
1139 {
1140         register queue_t *q;
1141 
1142         /* Flush pending data already sent upstream */
1143         if ((q = upper->kbtrans_streams_readq) != NULL && q->q_next != NULL)
1144                 (void) putnextctl1(q, M_FLUSH, FLUSHR);
1145 
1146         /* Flush pending ups */
1147         bzero(upper->kbtrans_streams_downs, upper->kbtrans_streams_downs_bytes);
1148 
1149         kbtrans_cancelrpt(upper);
1150 }
1151 
1152 /*
1153  * kbtrans_setled:
1154  *       Update the keyboard LEDs to match the current keyboard state.
1155  */
1156 static void
1157 kbtrans_setled(struct kbtrans *upper)
1158 {
1159         upper->kbtrans_streams_hw_callbacks->kbtrans_streams_setled(
1160             upper->kbtrans_streams_hw,
1161             upper->kbtrans_lower.kbtrans_led_state);
1162 }
1163 
1164 /*
1165  * kbtrans_rpt:
1166  *      If a key is held down, this function is set up to be called
1167  *      after kbtrans_repeat_rate time elapses.
1168  */
1169 static void
1170 kbtrans_rpt(void *arg)
1171 {
1172         struct kbtrans  *upper = arg;
1173         struct kbtrans_lower    *lower = &upper->kbtrans_lower;
1174 
1175         DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL,
1176             "kbtrans_rpt: repeat key %X\n",
1177             lower->kbtrans_repeatkey));
1178 
1179         upper->kbtrans_streams_rptid = 0;
1180 
1181         /*
1182          * NB:  polled code zaps kbtrans_repeatkey without cancelling
1183          * timeout.
1184          */
1185         if (lower->kbtrans_repeatkey != 0) {
1186                 kbtrans_keyreleased(upper, lower->kbtrans_repeatkey);
1187 
1188                 kbtrans_processkey(lower,
1189                     upper->kbtrans_streams_callback,
1190                     lower->kbtrans_repeatkey,
1191                     KEY_PRESSED);
1192 
1193                 upper->kbtrans_streams_rptid =
1194                     qtimeout(upper->kbtrans_streams_readq, kbtrans_rpt,
1195                     (caddr_t)upper, kbtrans_repeat_rate);
1196         }
1197 }
1198 
1199 /*
1200  * kbtrans_cancelrpt:
1201  *      Cancel the repeating key
1202  */
1203 static void
1204 kbtrans_cancelrpt(struct kbtrans        *upper)
1205 {
1206         upper->kbtrans_lower.kbtrans_repeatkey = 0;
1207 
1208         if (upper->kbtrans_streams_rptid != 0) {
1209                 (void) quntimeout(upper->kbtrans_streams_readq,
1210                     upper->kbtrans_streams_rptid);
1211                 upper->kbtrans_streams_rptid = 0;
1212         }
1213 }
1214 
1215 /*
1216  * kbtrans_send_esc_event:
1217  *      Send character up stream. Used for the case of
1218  *      sending strings upstream.
1219  */
1220 static void
1221 kbtrans_send_esc_event(char c, register struct kbtrans *upper)
1222 {
1223         Firm_event fe;
1224 
1225         fe.id = c;
1226         fe.value = 1;
1227         fe.pair_type = FE_PAIR_NONE;
1228         fe.pair = 0;
1229         /*
1230          * Pretend as if each cp pushed and released
1231          * Calling kbtrans_queueevent avoids addr translation
1232          * and pair base determination of kbtrans_keypressed.
1233          */
1234         kbtrans_queueevent(upper, &fe);
1235         fe.value = 0;
1236         kbtrans_queueevent(upper, &fe);
1237 }
1238 
1239 /*
1240  * kbtrans_strsetwithdecimal:
1241  *      Used for expanding a function key to the ascii equivalent
1242  */
1243 static char *
1244 kbtrans_strsetwithdecimal(char *buf, uint_t val, uint_t maxdigs)
1245 {
1246         int     hradix = 5;
1247         char    *bp;
1248         int     lowbit;
1249         char    *tab = "0123456789abcdef";
1250 
1251         bp = buf + maxdigs;
1252         *(--bp) = '\0';
1253         while (val) {
1254                 lowbit = val & 1;
1255                 val = (val >> 1);
1256                 *(--bp) = tab[val % hradix * 2 + lowbit];
1257                 val /= hradix;
1258         }
1259         return (bp);
1260 }
1261 
1262 /*
1263  * kbtrans_keypressed:
1264  *      Modify Firm event to be sent up the stream
1265  */
1266 static void
1267 kbtrans_keypressed(struct kbtrans *upper, uchar_t key_station,
1268                     Firm_event *fe, ushort_t base)
1269 {
1270 
1271         register short  id_addr;
1272         struct kbtrans_lower    *lower = &upper->kbtrans_lower;
1273 
1274         /* Set pair values */
1275         if (fe->id < (ushort_t)VKEY_FIRST) {
1276                 /*
1277                  * If CTRLed, find the ID that would have been used had it
1278                  * not been CTRLed.
1279                  */
1280                 if (lower->kbtrans_shiftmask & (CTRLMASK | CTLSMASK)) {
1281                         unsigned short *ke;
1282                         unsigned int mask;
1283 
1284                         mask = lower->kbtrans_shiftmask &
1285                             ~(CTRLMASK | CTLSMASK | UPMASK);
1286 
1287                         ke = kbtrans_find_entry(lower, mask, key_station);
1288                         if (ke == NULL)
1289                                 return;
1290 
1291                         base = *ke;
1292                 }
1293                 if (base != fe->id) {
1294                         fe->pair_type = FE_PAIR_SET;
1295                         fe->pair = (uchar_t)base;
1296 
1297                         goto send;
1298                 }
1299         }
1300         fe->pair_type = FE_PAIR_NONE;
1301         fe->pair = 0;
1302 
1303 send:
1304         /* Adjust event id address for multiple keyboard/workstation support */
1305         switch (vuid_id_addr(fe->id)) {
1306         case ASCII_FIRST:
1307                 id_addr = upper->kbtrans_streams_vuid_addr.ascii;
1308                 break;
1309         case TOP_FIRST:
1310                 id_addr = upper->kbtrans_streams_vuid_addr.top;
1311                 break;
1312         case VKEY_FIRST:
1313                 id_addr = upper->kbtrans_streams_vuid_addr.vkey;
1314                 break;
1315         default:
1316                 id_addr = vuid_id_addr(fe->id);
1317                 break;
1318         }
1319         fe->id = vuid_id_offset(fe->id) | id_addr;
1320 
1321         kbtrans_queuepress(upper, key_station, fe);
1322 }
1323 
1324 /*
1325  * kbtrans_queuepress:
1326  *      Add keypress to the "downs" table
1327  */
1328 static void
1329 kbtrans_queuepress(struct kbtrans *upper,
1330                     uchar_t key_station, Firm_event *fe)
1331 {
1332         register struct key_event *ke, *ke_free;
1333         register int i;
1334 
1335         DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL, "kbtrans_queuepress:"
1336             " key=%d", key_station));
1337 
1338         ke_free = 0;
1339 
1340         /* Scan table of down key stations */
1341 
1342         for (i = 0, ke = upper->kbtrans_streams_downs;
1343             i < upper->kbtrans_streams_num_downs_entries; i++, ke++) {
1344 
1345                 /* Keycode already down? */
1346                 if (ke->key_station == key_station) {
1347 
1348                         DPRINTF(PRINT_L0, PRINT_MASK_ALL,
1349                             (NULL, "kbtrans: Double "
1350                             "entry in downs table (%d,%d)!\n",
1351                             key_station, i));
1352 
1353                         goto add_event;
1354                 }
1355 
1356                 if (ke->key_station == 0)
1357                         ke_free = ke;
1358         }
1359 
1360         if (ke_free) {
1361                 ke = ke_free;
1362                 goto add_event;
1363         }
1364 
1365         ke = upper->kbtrans_streams_downs;
1366 
1367 add_event:
1368         ke->key_station = key_station;
1369         ke->event = *fe;
1370         kbtrans_queueevent(upper, fe);
1371 }
1372 
1373 /*
1374  * kbtrans_keyreleased:
1375  *      Remove entry from the downs table
1376  */
1377 static void
1378 kbtrans_keyreleased(register struct kbtrans *upper, uchar_t key_station)
1379 {
1380         register struct key_event *ke;
1381         register int i;
1382 
1383         DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL, "RELEASE key=%d\n",
1384             key_station));
1385 
1386         if (upper->kbtrans_streams_translate_mode != TR_EVENT &&
1387             upper->kbtrans_streams_translate_mode != TR_UNTRANS_EVENT) {
1388 
1389                 return;
1390         }
1391 
1392         /* Scan table of down key stations */
1393         for (i = 0, ke = upper->kbtrans_streams_downs;
1394             i < upper->kbtrans_streams_num_downs_entries;
1395             i++, ke++) {
1396                 /* Found? */
1397                 if (ke->key_station == key_station) {
1398                         ke->key_station = 0;
1399                         ke->event.value = 0;
1400                         kbtrans_queueevent(upper, &ke->event);
1401                 }
1402         }
1403 
1404         /*
1405          * Ignore if couldn't find because may be called twice
1406          * for the same key station in the case of the kbtrans_rpt
1407          * routine being called unnecessarily.
1408          */
1409 }
1410 
1411 
1412 /*
1413  * kbtrans_putcode:
1414  *       Pass a keycode up the stream, if you can, otherwise throw it away.
1415  */
1416 static void
1417 kbtrans_putcode(register struct kbtrans *upper, uint_t code)
1418 {
1419         register mblk_t *bp;
1420 
1421         /*
1422          * If we can't send it up, then we just drop it.
1423          */
1424         if (!canputnext(upper->kbtrans_streams_readq)) {
1425 
1426                 return;
1427         }
1428 
1429         /*
1430          * Allocate a messsage block to send up.
1431          */
1432         if ((bp = allocb(sizeof (uint_t), BPRI_HI)) == NULL) {
1433 
1434                 cmn_err(CE_WARN, "kbtrans_putcode: Can't allocate block\
1435                         for keycode.");
1436 
1437                 return;
1438         }
1439 
1440         /*
1441          * We will strip out any high order information here.
1442          */
1443         /* NOTE the implicit cast here */
1444         *bp->b_wptr++ = (uchar_t)code;
1445 
1446         /*
1447          * Send the message up.
1448          */
1449         (void) putnext(upper->kbtrans_streams_readq, bp);
1450 }
1451 
1452 
1453 /*
1454  * kbtrans_putbuf:
1455  *      Pass generated keycode sequence to upstream, if possible.
1456  */
1457 static void
1458 kbtrans_putbuf(char *buf, queue_t *q)
1459 {
1460         register mblk_t *bp;
1461 
1462         if (!canputnext(q)) {
1463                 cmn_err(CE_WARN, "kbtrans_putbuf: Can't put block for keycode");
1464         } else {
1465                 if ((bp = allocb((int)strlen(buf), BPRI_HI)) == NULL) {
1466                         cmn_err(CE_WARN, "kbtrans_putbuf: "
1467                             "Can't allocate block for keycode");
1468                 } else {
1469                         while (*buf) {
1470                                 *bp->b_wptr++ = *buf;
1471                                 buf++;
1472                         }
1473                         putnext(q, bp);
1474                 }
1475         }
1476 }
1477 
1478 /*
1479  * kbtrans_queueevent:
1480  *       Pass a VUID "firm event" up the stream, if you can.
1481  */
1482 static void
1483 kbtrans_queueevent(struct kbtrans *upper, Firm_event *fe)
1484 {
1485         register queue_t *q;
1486         register mblk_t *bp;
1487 
1488         if ((q = upper->kbtrans_streams_readq) == NULL)
1489 
1490                 return;
1491 
1492         if (!canputnext(q)) {
1493                 if (kbtrans_overflow_msg) {
1494                         DPRINTF(PRINT_L2, PRINT_MASK_ALL, (NULL,
1495                             "kbtrans: Buffer flushed when overflowed."));
1496                 }
1497 
1498                 kbtrans_flush(upper);
1499                 upper->kbtrans_overflow_cnt++;
1500         } else {
1501                 if ((bp = allocb(sizeof (Firm_event), BPRI_HI)) == NULL) {
1502                         cmn_err(CE_WARN, "kbtrans_queueevent: Can't allocate \
1503                                         block for event.");
1504                 } else {
1505                         uniqtime32(&fe->time);
1506                         *(Firm_event *)bp->b_wptr = *fe;
1507                         bp->b_wptr += sizeof (Firm_event);
1508                         (void) putnext(q, bp);
1509 
1510 
1511                 }
1512         }
1513 }
1514 
1515 /*
1516  * kbtrans_set_translation_callback:
1517  *      This code sets the translation_callback pointer based on the
1518  *      translation mode.
1519  */
1520 static void
1521 kbtrans_set_translation_callback(register struct kbtrans *upper)
1522 {
1523         switch (upper->kbtrans_streams_translate_mode) {
1524 
1525         default:
1526         case TR_ASCII:
1527                 upper->vt_switch_keystate = VT_SWITCH_KEY_NONE;
1528 
1529                 /* Discard any obsolete CTRL/ALT/SHIFT keys */
1530                 upper->kbtrans_lower.kbtrans_shiftmask &=
1531                     ~(CTRLMASK | ALTMASK | SHIFTMASK);
1532                 upper->kbtrans_lower.kbtrans_togglemask &=
1533                     ~(CTRLMASK | ALTMASK | SHIFTMASK);
1534 
1535                 upper->kbtrans_streams_callback = &ascii_callback;
1536 
1537                 break;
1538 
1539         case TR_EVENT:
1540                 upper->kbtrans_streams_callback = &trans_event_callback;
1541 
1542                 break;
1543 
1544         case TR_UNTRANS_EVENT:
1545                 upper->kbtrans_streams_callback = &untrans_event_callback;
1546 
1547                 break;
1548         }
1549 }
1550 
1551 /*
1552  * kbtrans_untrans_keypressed_raw:
1553  *      This is the callback we get if we are in TR_UNTRANS_EVENT and a
1554  *      key is pressed.  This code will just send the scancode up the
1555  *      stream.
1556  */
1557 static void
1558 kbtrans_untrans_keypressed_raw(struct kbtrans *upper, kbtrans_key_t key)
1559 {
1560         Firm_event      fe;
1561 
1562         bzero(&fe, sizeof (fe));
1563 
1564         /*
1565          * fill in the event
1566          */
1567         fe.id = (unsigned short)key;
1568         fe.value = 1;
1569 
1570         /*
1571          * Send the event upstream.
1572          */
1573         kbtrans_queuepress(upper, key, &fe);
1574 }
1575 
1576 /*
1577  * kbtrans_untrans_keyreleased_raw:
1578  *      This is the callback we get if we are in TR_UNTRANS_EVENT mode
1579  *      and a key is released.  This code will just send the scancode up
1580  *      the stream.
1581  */
1582 static void
1583 kbtrans_untrans_keyreleased_raw(struct kbtrans *upper, kbtrans_key_t key)
1584 {
1585         /*
1586          * Deal with a key released event.
1587          */
1588         kbtrans_keyreleased(upper, key);
1589 }
1590 
1591 /*
1592  * kbtrans_vt_compose:
1593  *   To compose the key sequences for virtual terminal switching.
1594  *
1595  *   'ALTL + F#'                for 1-12 terminals
1596  *   'ALTGR + F#'               for 13-24 terminals
1597  *   'ALT + UPARROW'            for last terminal
1598  *   'ALT + LEFTARROW'          for previous terminal
1599  *   'ALT + RIGHTARROW'         for next terminal
1600  *
1601  * the vt switching message is encoded as:
1602  *
1603  *   -------------------------------------------------------------
1604  *   |  \033  |  'Q'  |  vtno + 'A'  |  opcode  |  'z'  |  '\0'  |
1605  *   -------------------------------------------------------------
1606  *
1607  * opcode:
1608  *   'B'    to switch to previous terminal
1609  *   'F'    to switch to next terminal
1610  *   'L'    to switch to last terminal
1611  *   'H'    to switch to the terminal as specified by vtno,
1612  *          which is from 1 to 24.
1613  *
1614  * Here keyid is the keycode of UPARROW, LEFTARROW, or RIGHTARROW
1615  * when it is a kind of arrow key as indicated by is_arrow_key,
1616  * otherwise it indicates a function key and keyid is the number
1617  * corresponding to that function key.
1618  */
1619 static void
1620 kbtrans_vt_compose(struct kbtrans *upper, unsigned short keyid,
1621     boolean_t is_arrow_key, char *buf)
1622 {
1623         char            *bufp;
1624 
1625         bufp = buf;
1626         *bufp++ = '\033'; /* Escape */
1627         *bufp++ = 'Q';
1628         if (is_arrow_key) {
1629                 *bufp++ = 'A';
1630                 switch (keyid) {
1631                 case UPARROW: /* last vt */
1632                         *bufp++ = 'L';
1633                         break;
1634                 case LEFTARROW: /* previous vt */
1635                         *bufp++ = 'B';
1636                         break;
1637                 case RIGHTARROW: /* next vt */
1638                         *bufp++ = 'F';
1639                         break;
1640                 default:
1641                         break;
1642                 }
1643         } else {
1644                 /* this is funckey specifying vtno for switch */
1645                 *bufp++ = keyid +
1646                     (upper->vt_switch_keystate - VT_SWITCH_KEY_ALT) *
1647                     KB_NR_FUNCKEYS + 'A';
1648                 *bufp++ = 'H';
1649         }
1650         *bufp++ = 'z';
1651         *bufp = '\0';
1652 
1653         /*
1654          * Send the result upstream.
1655          */
1656         kbtrans_putbuf(buf, upper->kbtrans_streams_readq);
1657 
1658 }
1659 
1660 /*
1661  * kbtrans_ascii_keypressed:
1662  *      This is the code if we are in TR_ASCII mode and a key
1663  *      is pressed.  This is where we will do any special processing that
1664  *      is specific to ASCII key translation.
1665  */
1666 /* ARGSUSED */
1667 static void
1668 kbtrans_ascii_keypressed(
1669     struct kbtrans      *upper,
1670     uint_t              entrytype,
1671     kbtrans_key_t       key,
1672     uint_t              entry)
1673 {
1674         register char   *cp;
1675         register char   *bufp;
1676         char            buf[14];
1677         unsigned short          keyid;
1678         struct kbtrans_lower    *lower = &upper->kbtrans_lower;
1679 
1680         /*
1681          * Based on the type of key, we may need to do some ASCII
1682          * specific post processing. Note that the translated entry
1683          * is constructed as the actual keycode plus entrytype. see
1684          * sys/kbd.h for details of each entrytype.
1685          */
1686         switch (entrytype) {
1687 
1688         case BUCKYBITS:
1689                 return;
1690 
1691         case SHIFTKEYS:
1692                 keyid = entry & 0xFF;
1693                 if (keyid == ALT) {
1694                         upper->vt_switch_keystate = VT_SWITCH_KEY_ALT;
1695                 } else if (keyid == ALTGRAPH) {
1696                         upper->vt_switch_keystate = VT_SWITCH_KEY_ALTGR;
1697                 }
1698                 return;
1699 
1700         case FUNNY:
1701                 /*
1702                  * There is no ascii equivalent.  We will ignore these
1703                  * keys
1704                  */
1705                 return;
1706 
1707         case FUNCKEYS:
1708                 if (upper->vt_switch_keystate > VT_SWITCH_KEY_NONE) {
1709                         if (entry >= TOPFUNC &&
1710                             entry < (TOPFUNC + KB_NR_FUNCKEYS)) {
1711 
1712                                 /*
1713                                  * keyid is the number correspoding to F#
1714                                  * and its value is from 1 to 12.
1715                                  */
1716                                 keyid = (entry & 0xF) + 1;
1717 
1718                                 kbtrans_vt_compose(upper, keyid, B_FALSE, buf);
1719                                 return;
1720                         }
1721                 }
1722 
1723                 /*
1724                  * We need to expand this key to get the ascii
1725                  * equivalent.  These are the function keys (F1, F2 ...)
1726                  */
1727                 bufp = buf;
1728                 cp = kbtrans_strsetwithdecimal(bufp + 2,
1729                     (uint_t)((entry & 0x003F) + 192),
1730                     sizeof (buf) - 5);
1731                 *bufp++ = '\033'; /* Escape */
1732                 *bufp++ = '[';
1733                 while (*cp != '\0')
1734                         *bufp++ = *cp++;
1735                 *bufp++ = 'z';
1736                 *bufp = '\0';
1737 
1738                 /*
1739                  * Send the result upstream.
1740                  */
1741                 kbtrans_putbuf(buf, upper->kbtrans_streams_readq);
1742 
1743                 return;
1744 
1745         case STRING:
1746                 if (upper->vt_switch_keystate > VT_SWITCH_KEY_NONE) {
1747                         keyid = entry & 0xFF;
1748                         if (keyid == UPARROW ||
1749                             keyid == RIGHTARROW ||
1750                             keyid == LEFTARROW) {
1751 
1752                                 kbtrans_vt_compose(upper, keyid, B_TRUE, buf);
1753                                 return;
1754                         }
1755                 }
1756 
1757                 /*
1758                  * These are the multi byte keys (Home, Up, Down ...)
1759                  */
1760                 cp = &lower->kbtrans_keystringtab[entry & 0x0F][0];
1761 
1762                 /*
1763                  * Copy the string from the keystringtable, and send it
1764                  * upstream a character at a time.
1765                  */
1766                 while (*cp != '\0') {
1767 
1768                         kbtrans_putcode(upper, (uchar_t)*cp);
1769 
1770                         cp++;
1771                 }
1772 
1773                 return;
1774 
1775         case PADKEYS:
1776                 /*
1777                  * These are the keys on the keypad.  Look up the
1778                  * answer in the kb_numlock_table and send it upstream.
1779                  */
1780                 kbtrans_putcode(upper,
1781                     lower->kbtrans_numlock_table[entry&0x1F]);
1782 
1783                 return;
1784 
1785         case 0: /* normal character */
1786         default:
1787                 break;
1788         }
1789 
1790         /*
1791          * Send the byte upstream.
1792          */
1793         kbtrans_putcode(upper, entry);
1794 
1795 }
1796 
1797 #define KB_SCANCODE_ALT         0xe2
1798 #define KB_SCANCODE_ALTGRAPH    0xe6
1799 
1800 /*
1801  * kbtrans_ascii_keyreleased:
1802  *      This is the function if we are in TR_ASCII mode and a key
1803  *      is released.  ASCII doesn't have the concept of released keys,
1804  *      or make/break codes.  So there is nothing for us to do except
1805  *      checking 'Alt/AltGraph' release key in order to reset the state
1806  *      of vt switch key sequence.
1807  */
1808 /* ARGSUSED */
1809 static void
1810 kbtrans_ascii_keyreleased(struct kbtrans *upper, kbtrans_key_t key)
1811 {
1812         if (key == KB_SCANCODE_ALT || key == KB_SCANCODE_ALTGRAPH) {
1813                 upper->vt_switch_keystate = VT_SWITCH_KEY_NONE;
1814         }
1815 }
1816 
1817 /*
1818  * kbtrans_ascii_setup_repeat:
1819  *      This is the function if we are in TR_ASCII mode and the
1820  *      translation module has decided that a key needs to be repeated.
1821  */
1822 /* ARGSUSED */
1823 static void
1824 kbtrans_ascii_setup_repeat(
1825     struct kbtrans *upper,
1826     uint_t entrytype,
1827     kbtrans_key_t key)
1828 {
1829         struct kbtrans_lower *lower = &upper->kbtrans_lower;
1830 
1831         /*
1832          * Cancel any currently repeating keys.  This will be a new
1833          * key to repeat.
1834          */
1835         kbtrans_cancelrpt(upper);
1836 
1837         /*
1838          * Set the value of the key to be repeated.
1839          */
1840         lower->kbtrans_repeatkey = key;
1841 
1842         /*
1843          * Start the timeout for repeating this key.  kbtrans_rpt will
1844          * be called to repeat the key.
1845          */
1846         upper->kbtrans_streams_rptid = qtimeout(upper->kbtrans_streams_readq,
1847             kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
1848 }
1849 
1850 /*
1851  * kbtrans_trans_event_keypressed:
1852  *      This is the function if we are in TR_EVENT mode and a key
1853  *      is pressed.  This is where we will do any special processing that
1854  *      is specific to EVENT key translation.
1855  */
1856 static void
1857 kbtrans_trans_event_keypressed(
1858         struct kbtrans  *upper,
1859         uint_t          entrytype,
1860         kbtrans_key_t   key,
1861         uint_t          entry)
1862 {
1863         Firm_event      fe;
1864         register char   *cp;
1865         struct kbtrans_lower    *lower = &upper->kbtrans_lower;
1866 
1867         /*
1868          * Based on the type of key, we may need to do some EVENT
1869          * specific post processing.
1870          */
1871         switch (entrytype) {
1872 
1873         case SHIFTKEYS:
1874                 /*
1875                  * Relying on ordinal correspondence between
1876                  * vuid_event.h SHIFT_META-SHIFT_TOP &
1877                  * kbd.h METABIT-SYSTEMBIT in order to
1878                  * correctly translate entry into fe.id.
1879                  */
1880                 fe.id = SHIFT_CAPSLOCK + (entry & 0x0F);
1881                 fe.value = 1;
1882                 kbtrans_keypressed(upper, key, &fe, fe.id);
1883 
1884                 return;
1885 
1886         case BUCKYBITS:
1887                 /*
1888                  * Relying on ordinal correspondence between
1889                  * vuid_event.h SHIFT_CAPSLOCK-SHIFT_RIGHTCTRL &
1890                  * kbd.h CAPSLOCK-RIGHTCTRL in order to
1891                  * correctly translate entry into fe.id.
1892                  */
1893                 fe.id = SHIFT_META + (entry & 0x0F);
1894                 fe.value = 1;
1895                 kbtrans_keypressed(upper, key, &fe, fe.id);
1896 
1897                 return;
1898 
1899         case FUNCKEYS:
1900                 /*
1901                  * Take advantage of the similar
1902                  * ordering of kbd.h function keys and
1903                  * vuid_event.h function keys to do a
1904                  * simple translation to achieve a
1905                  * mapping between the 2 different
1906                  * address spaces.
1907                  */
1908                 fe.id = KEY_LEFTFIRST + (entry & 0x003F);
1909                 fe.value = 1;
1910 
1911                 /*
1912                  * Assume "up" table only generates
1913                  * shift changes.
1914                  */
1915                 kbtrans_keypressed(upper, key, &fe, fe.id);
1916 
1917                 /*
1918                  * Function key events can be expanded
1919                  * by terminal emulator software to
1920                  * produce the standard escape sequence
1921                  * generated by the TR_ASCII case above
1922                  * if a function key event is not used
1923                  * by terminal emulator software
1924                  * directly.
1925                  */
1926                 return;
1927 
1928         case STRING:
1929                 /*
1930                  * These are the multi byte keys (Home, Up, Down ...)
1931                  */
1932                 cp = &lower->kbtrans_keystringtab[entry & 0x0F][0];
1933 
1934                 /*
1935                  * Copy the string from the keystringtable, and send it
1936                  * upstream a character at a time.
1937                  */
1938                 while (*cp != '\0') {
1939 
1940                         kbtrans_send_esc_event(*cp, upper);
1941 
1942                         cp++;
1943                 }
1944 
1945                 return;
1946 
1947         case PADKEYS:
1948                 /*
1949                  * Take advantage of the similar
1950                  * ordering of kbd.h keypad keys and
1951                  * vuid_event.h keypad keys to do a
1952                  * simple translation to achieve a
1953                  * mapping between the 2 different
1954                  * address spaces.
1955                  */
1956                 fe.id = VKEY_FIRSTPAD + (entry & 0x001F);
1957                 fe.value = 1;
1958 
1959                 /*
1960                  * Assume "up" table only generates
1961                  * shift changes.
1962                  */
1963                 kbtrans_keypressed(upper, key, &fe, fe.id);
1964 
1965                 /*
1966                  * Keypad key events can be expanded
1967                  * by terminal emulator software to
1968                  * produce the standard ascii character
1969                  * generated by the TR_ASCII case above
1970                  * if a keypad key event is not used
1971                  * by terminal emulator software
1972                  * directly.
1973                  */
1974                 return;
1975 
1976         case FUNNY:
1977                 /*
1978                  * These are not events.
1979                  */
1980                 switch (entry) {
1981                 case IDLE:
1982                 case RESET:
1983                 case ERROR:
1984                         /*
1985                          * Something has happened.  Mark all keys as released.
1986                          */
1987                         kbtrans_streams_releaseall(upper);
1988                         break;
1989                 }
1990 
1991                 return;
1992 
1993         case 0: /* normal character */
1994         default:
1995                 break;
1996         }
1997 
1998         /*
1999          * Send the event upstream.
2000          */
2001         fe.id = entry;
2002 
2003         fe.value = 1;
2004 
2005         kbtrans_queueevent(upper, &fe);
2006 }
2007 
2008 /*
2009  * kbtrans_trans_event_keyreleased:
2010  *      This is the function if we are in TR_EVENT mode and a key
2011  *      is released.
2012  */
2013 /* ARGSUSED */
2014 static void
2015 kbtrans_trans_event_keyreleased(struct kbtrans *upper, kbtrans_key_t key)
2016 {
2017         /*
2018          * Mark the key as released and send an event upstream.
2019          */
2020         kbtrans_keyreleased(upper, key);
2021 }
2022 
2023 /*
2024  * kbtrans_trans_event_setup_repeat:
2025  *      This is the function if we are in TR_EVENT mode and the
2026  *      translation module has decided that a key needs to be repeated.
2027  *      We will set a timeout to retranslate the repeat key.
2028  */
2029 static void
2030 kbtrans_trans_event_setup_repeat(
2031         struct kbtrans  *upper,
2032         uint_t          entrytype,
2033         kbtrans_key_t   key)
2034 {
2035         struct kbtrans_lower *lower = &upper->kbtrans_lower;
2036 
2037         /*
2038          * Function keys and keypad keys do not repeat when we are in
2039          * EVENT mode.
2040          */
2041         if (entrytype == FUNCKEYS || entrytype == PADKEYS) {
2042 
2043                 return;
2044         }
2045 
2046         /*
2047          * Cancel any currently repeating keys.  This will be a new
2048          * key to repeat.
2049          */
2050         kbtrans_cancelrpt(upper);
2051 
2052         /*
2053          * Set the value of the key to be repeated.
2054          */
2055         lower->kbtrans_repeatkey = key;
2056 
2057         /*
2058          * Start the timeout for repeating this key.  kbtrans_rpt will
2059          * be called to repeat the key.
2060          */
2061         upper->kbtrans_streams_rptid = qtimeout(upper->kbtrans_streams_readq,
2062             kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
2063 }
2064 
2065 /*
2066  * Administer the key tables.
2067  */
2068 
2069 /*
2070  * Old special codes.
2071  */
2072 #define OLD_SHIFTKEYS   0x80
2073 #define OLD_BUCKYBITS   0x90
2074 #define OLD_FUNNY       0xA0
2075 #define OLD_FA_UMLAUT   0xA9
2076 #define OLD_FA_CFLEX    0xAA
2077 #define OLD_FA_TILDE    0xAB
2078 #define OLD_FA_CEDILLA  0xAC
2079 #define OLD_FA_ACUTE    0xAD
2080 #define OLD_FA_GRAVE    0xAE
2081 #define OLD_ISOCHAR     0xAF
2082 #define OLD_STRING      0xB0
2083 #define OLD_LEFTFUNC    0xC0
2084 #define OLD_RIGHTFUNC   0xD0
2085 #define OLD_TOPFUNC     0xE0
2086 #define OLD_BOTTOMFUNC  0xF0
2087 
2088 /*
2089  * Map old special codes to new ones.
2090  * Indexed by ((old special code) >> 4) & 0x07; add (old special code) & 0x0F.
2091  */
2092 static ushort_t  special_old_to_new[] = {
2093         SHIFTKEYS,
2094         BUCKYBITS,
2095         FUNNY,
2096         STRING,
2097         LEFTFUNC,
2098         RIGHTFUNC,
2099         TOPFUNC,
2100         BOTTOMFUNC,
2101 };
2102 
2103 
2104 /*
2105  * kbtrans_setkey:
2106  *       Set individual keystation translation from old-style entry.
2107  */
2108 static int
2109 kbtrans_setkey(struct kbtrans_lower *lower, struct kiockey *key, cred_t *cr)
2110 {
2111         int     strtabindex, i;
2112         unsigned short  *ke;
2113         register int tablemask;
2114         register ushort_t entry;
2115         register struct keyboard *kp;
2116 
2117         kp = lower->kbtrans_keyboard;
2118 
2119         if (key->kio_station >= kp->k_keymap_size)
2120 
2121                 return (EINVAL);
2122 
2123         if (lower->kbtrans_keyboard == NULL)
2124 
2125                 return (EINVAL);
2126 
2127         tablemask = key->kio_tablemask;
2128 
2129         switch (tablemask) {
2130         case KIOCABORT1:
2131         case KIOCABORT1A:
2132         case KIOCABORT2:
2133                 i = secpolicy_console(cr);
2134                 if (i != 0)
2135                         return (i);
2136 
2137                 switch (tablemask) {
2138                 case KIOCABORT1:
2139                         kp->k_abort1 = key->kio_station;
2140                         break;
2141                 case KIOCABORT1A:
2142                         kp->k_abort1a = key->kio_station;
2143                         break;
2144                 case KIOCABORT2:
2145                         kp->k_abort2 = key->kio_station;
2146                         break;
2147                 }
2148                 return (0);
2149         }
2150 
2151         if (tablemask & ALTGRAPHMASK)
2152                 return (EINVAL);
2153 
2154         ke = kbtrans_find_entry(lower, (uint_t)tablemask, key->kio_station);
2155         if (ke == NULL)
2156                 return (EINVAL);
2157 
2158         if (key->kio_entry >= (uchar_t)OLD_STRING &&
2159             key->kio_entry <= (uchar_t)(OLD_STRING + 15)) {
2160                 strtabindex = key->kio_entry - OLD_STRING;
2161                 bcopy(key->kio_string,
2162                     lower->kbtrans_keystringtab[strtabindex], KTAB_STRLEN);
2163                 lower->kbtrans_keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
2164         }
2165 
2166         entry = key->kio_entry;
2167 
2168         /*
2169          * There's nothing we need do with OLD_ISOCHAR.
2170          */
2171         if (entry != OLD_ISOCHAR) {
2172                 if (entry & 0x80) {
2173                         if (entry >= OLD_FA_UMLAUT && entry <= OLD_FA_GRAVE)
2174                                 entry = FA_CLASS + (entry & 0x0F) - 9;
2175                         else
2176                                 entry =
2177                                     special_old_to_new[entry >> 4 & 0x07]
2178                                     + (entry & 0x0F);
2179                 }
2180         }
2181 
2182         *ke = entry;
2183 
2184         return (0);
2185 }
2186 
2187 
2188 /*
2189  * Map new special codes to old ones.
2190  * Indexed by (new special code) >> 8; add (new special code) & 0xFF.
2191  */
2192 static uchar_t   special_new_to_old[] = {
2193         0,                      /* normal */
2194         OLD_SHIFTKEYS,          /* SHIFTKEYS */
2195         OLD_BUCKYBITS,          /* BUCKYBITS */
2196         OLD_FUNNY,              /* FUNNY */
2197         OLD_FA_UMLAUT,          /* FA_CLASS */
2198         OLD_STRING,             /* STRING */
2199         OLD_LEFTFUNC,           /* FUNCKEYS */
2200 };
2201 
2202 
2203 /*
2204  * kbtrans_getkey:
2205  *      Get individual keystation translation as old-style entry.
2206  */
2207 static int
2208 kbtrans_getkey(struct kbtrans_lower *lower, struct kiockey *key)
2209 {
2210         int     strtabindex;
2211         unsigned short  *ke;
2212         register ushort_t entry;
2213         struct keyboard *kp;
2214 
2215         kp = lower->kbtrans_keyboard;
2216 
2217         if (key->kio_station >= kp->k_keymap_size)
2218                 return (EINVAL);
2219 
2220         if (lower->kbtrans_keyboard == NULL)
2221                 return (EINVAL);
2222 
2223         switch (key->kio_tablemask) {
2224         case KIOCABORT1:
2225                 key->kio_station = kp->k_abort1;
2226                 return (0);
2227         case KIOCABORT1A:
2228                 key->kio_station = kp->k_abort1a;
2229                 return (0);
2230         case KIOCABORT2:
2231                 key->kio_station = kp->k_abort2;
2232                 return (0);
2233         }
2234 
2235         ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2236             key->kio_station);
2237         if (ke == NULL)
2238                 return (EINVAL);
2239 
2240         entry = *ke;
2241 
2242         if (entry & 0xFF00)
2243                 key->kio_entry =
2244                     special_new_to_old[(ushort_t)(entry & 0xFF00) >> 8]
2245                     + (entry & 0x00FF);
2246         else {
2247                 if (entry & 0x80)
2248                         key->kio_entry = (ushort_t)OLD_ISOCHAR;      /* you lose */
2249                 else
2250                         key->kio_entry = (ushort_t)entry;
2251         }
2252 
2253         if (entry >= STRING && entry <= (uchar_t)(STRING + 15)) {
2254                 strtabindex = entry - STRING;
2255                 bcopy(lower->kbtrans_keystringtab[strtabindex],
2256                     key->kio_string, KTAB_STRLEN);
2257         }
2258         return (0);
2259 }
2260 
2261 
2262 /*
2263  * kbtrans_skey:
2264  *      Set individual keystation translation from new-style entry.
2265  */
2266 static int
2267 kbtrans_skey(struct kbtrans_lower *lower, struct kiockeymap *key, cred_t *cr)
2268 {
2269         int     strtabindex, i;
2270         unsigned short *ke;
2271         struct keyboard *kp;
2272 
2273         kp = lower->kbtrans_keyboard;
2274 
2275         if (key->kio_station >= kp->k_keymap_size) {
2276                 return (EINVAL);
2277 
2278         }
2279 
2280         if (lower->kbtrans_keyboard == NULL) {
2281                 return (EINVAL);
2282         }
2283 
2284         switch (key->kio_tablemask) {
2285         case KIOCABORT1:
2286         case KIOCABORT1A:
2287         case KIOCABORT2:
2288                 i = secpolicy_console(cr);
2289                 if (i != 0)
2290                         return (i);
2291                 switch (key->kio_tablemask) {
2292                 case KIOCABORT1:
2293                         kp->k_abort1 = key->kio_station;
2294                         break;
2295                 case KIOCABORT1A:
2296                         kp->k_abort1a = key->kio_station;
2297                         break;
2298                 case KIOCABORT2:
2299                         kp->k_abort2 = key->kio_station;
2300                         break;
2301                 }
2302                 return (0);
2303         }
2304 
2305         ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2306             key->kio_station);
2307         if (ke == NULL)
2308                 return (EINVAL);
2309 
2310         if (key->kio_entry >= STRING &&
2311             key->kio_entry <= (ushort_t)(STRING + 15)) {
2312                 strtabindex = key->kio_entry-STRING;
2313                 bcopy(key->kio_string,
2314                     lower->kbtrans_keystringtab[strtabindex], KTAB_STRLEN);
2315                 lower->kbtrans_keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
2316         }
2317 
2318         *ke = key->kio_entry;
2319 
2320         return (0);
2321 }
2322 
2323 
2324 /*
2325  * kbtrans_gkey:
2326  *      Get individual keystation translation as new-style entry.
2327  */
2328 static int
2329 kbtrans_gkey(struct kbtrans_lower *lower, struct        kiockeymap *key)
2330 {
2331         int     strtabindex;
2332         unsigned short *ke;
2333         struct keyboard *kp;
2334 
2335         kp = lower->kbtrans_keyboard;
2336 
2337         if (key->kio_station >= kp->k_keymap_size)
2338                 return (EINVAL);
2339 
2340         if (lower->kbtrans_keyboard == NULL)
2341                 return (EINVAL);
2342 
2343         switch (key->kio_tablemask) {
2344         case KIOCABORT1:
2345                 key->kio_station = kp->k_abort1;
2346                 return (0);
2347         case KIOCABORT1A:
2348                 key->kio_station = kp->k_abort1a;
2349                 return (0);
2350         case KIOCABORT2:
2351                 key->kio_station = kp->k_abort2;
2352                 return (0);
2353         }
2354 
2355         ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2356             key->kio_station);
2357         if (ke == NULL)
2358                 return (EINVAL);
2359 
2360         key->kio_entry = *ke;
2361 
2362         if (key->kio_entry >= STRING &&
2363             key->kio_entry <= (ushort_t)(STRING + 15)) {
2364                 strtabindex = key->kio_entry-STRING;
2365                 bcopy(lower->kbtrans_keystringtab[strtabindex],
2366                     key->kio_string, KTAB_STRLEN);
2367         }
2368         return (0);
2369 }