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                         keymap_entry_t *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          * Convert to UTF-8.
1443          */
1444         code = KEYCHAR(code);
1445         if (code < 0x80) {
1446                 *bp->b_wptr++ = (char)code;
1447         } else if (code < 0x800) {
1448                 *bp->b_wptr++ = 0xc0 | (code >> 6);
1449                 *bp->b_wptr++ = 0x80 | (code & 0x3f);
1450         } else if (code < 0x10000) {
1451                 *bp->b_wptr++ = 0xe0 | (code >> 12);
1452                 *bp->b_wptr++ = 0x80 | ((code >> 6) & 0x3f);
1453                 *bp->b_wptr++ = 0x80 | (code & 0x3f);
1454         } else {
1455                 *bp->b_wptr++ = 0xf0 | (code >> 18);
1456                 *bp->b_wptr++ = 0x80 | ((code >> 12) & 0x3f);
1457                 *bp->b_wptr++ = 0x80 | ((code >> 6) & 0x3f);
1458                 *bp->b_wptr++ = 0x80 | (code & 0x3f);
1459         }
1460 
1461         /*
1462          * Send the message up.
1463          */
1464         (void) putnext(upper->kbtrans_streams_readq, bp);
1465 }
1466 
1467 
1468 /*
1469  * kbtrans_putbuf:
1470  *      Pass generated keycode sequence to upstream, if possible.
1471  */
1472 static void
1473 kbtrans_putbuf(char *buf, queue_t *q)
1474 {
1475         register mblk_t *bp;
1476 
1477         if (!canputnext(q)) {
1478                 cmn_err(CE_WARN, "kbtrans_putbuf: Can't put block for keycode");
1479         } else {
1480                 if ((bp = allocb((int)strlen(buf), BPRI_HI)) == NULL) {
1481                         cmn_err(CE_WARN, "kbtrans_putbuf: "
1482                             "Can't allocate block for keycode");
1483                 } else {
1484                         while (*buf) {
1485                                 *bp->b_wptr++ = *buf;
1486                                 buf++;
1487                         }
1488                         putnext(q, bp);
1489                 }
1490         }
1491 }
1492 
1493 /*
1494  * kbtrans_queueevent:
1495  *       Pass a VUID "firm event" up the stream, if you can.
1496  */
1497 static void
1498 kbtrans_queueevent(struct kbtrans *upper, Firm_event *fe)
1499 {
1500         register queue_t *q;
1501         register mblk_t *bp;
1502 
1503         if ((q = upper->kbtrans_streams_readq) == NULL)
1504 
1505                 return;
1506 
1507         if (!canputnext(q)) {
1508                 if (kbtrans_overflow_msg) {
1509                         DPRINTF(PRINT_L2, PRINT_MASK_ALL, (NULL,
1510                             "kbtrans: Buffer flushed when overflowed."));
1511                 }
1512 
1513                 kbtrans_flush(upper);
1514                 upper->kbtrans_overflow_cnt++;
1515         } else {
1516                 if ((bp = allocb(sizeof (Firm_event), BPRI_HI)) == NULL) {
1517                         cmn_err(CE_WARN, "kbtrans_queueevent: Can't allocate \
1518                                         block for event.");
1519                 } else {
1520                         uniqtime32(&fe->time);
1521                         *(Firm_event *)bp->b_wptr = *fe;
1522                         bp->b_wptr += sizeof (Firm_event);
1523                         (void) putnext(q, bp);
1524 
1525 
1526                 }
1527         }
1528 }
1529 
1530 /*
1531  * kbtrans_set_translation_callback:
1532  *      This code sets the translation_callback pointer based on the
1533  *      translation mode.
1534  */
1535 static void
1536 kbtrans_set_translation_callback(register struct kbtrans *upper)
1537 {
1538         switch (upper->kbtrans_streams_translate_mode) {
1539 
1540         default:
1541         case TR_ASCII:
1542                 upper->vt_switch_keystate = VT_SWITCH_KEY_NONE;
1543 
1544                 /* Discard any obsolete CTRL/ALT/SHIFT keys */
1545                 upper->kbtrans_lower.kbtrans_shiftmask &=
1546                     ~(CTRLMASK | ALTMASK | SHIFTMASK);
1547                 upper->kbtrans_lower.kbtrans_togglemask &=
1548                     ~(CTRLMASK | ALTMASK | SHIFTMASK);
1549 
1550                 upper->kbtrans_streams_callback = &ascii_callback;
1551 
1552                 break;
1553 
1554         case TR_EVENT:
1555                 upper->kbtrans_streams_callback = &trans_event_callback;
1556 
1557                 break;
1558 
1559         case TR_UNTRANS_EVENT:
1560                 upper->kbtrans_streams_callback = &untrans_event_callback;
1561 
1562                 break;
1563         }
1564 }
1565 
1566 /*
1567  * kbtrans_untrans_keypressed_raw:
1568  *      This is the callback we get if we are in TR_UNTRANS_EVENT and a
1569  *      key is pressed.  This code will just send the scancode up the
1570  *      stream.
1571  */
1572 static void
1573 kbtrans_untrans_keypressed_raw(struct kbtrans *upper, kbtrans_key_t key)
1574 {
1575         Firm_event      fe;
1576 
1577         bzero(&fe, sizeof (fe));
1578 
1579         /*
1580          * fill in the event
1581          */
1582         fe.id = (unsigned short)key;
1583         fe.value = 1;
1584 
1585         /*
1586          * Send the event upstream.
1587          */
1588         kbtrans_queuepress(upper, key, &fe);
1589 }
1590 
1591 /*
1592  * kbtrans_untrans_keyreleased_raw:
1593  *      This is the callback we get if we are in TR_UNTRANS_EVENT mode
1594  *      and a key is released.  This code will just send the scancode up
1595  *      the stream.
1596  */
1597 static void
1598 kbtrans_untrans_keyreleased_raw(struct kbtrans *upper, kbtrans_key_t key)
1599 {
1600         /*
1601          * Deal with a key released event.
1602          */
1603         kbtrans_keyreleased(upper, key);
1604 }
1605 
1606 /*
1607  * kbtrans_vt_compose:
1608  *   To compose the key sequences for virtual terminal switching.
1609  *
1610  *   'ALTL + F#'                for 1-12 terminals
1611  *   'ALTGR + F#'               for 13-24 terminals
1612  *   'ALT + UPARROW'            for last terminal
1613  *   'ALT + LEFTARROW'          for previous terminal
1614  *   'ALT + RIGHTARROW'         for next terminal
1615  *
1616  * the vt switching message is encoded as:
1617  *
1618  *   -------------------------------------------------------------
1619  *   |  \033  |  'Q'  |  vtno + 'A'  |  opcode  |  'z'  |  '\0'  |
1620  *   -------------------------------------------------------------
1621  *
1622  * opcode:
1623  *   'B'    to switch to previous terminal
1624  *   'F'    to switch to next terminal
1625  *   'L'    to switch to last terminal
1626  *   'H'    to switch to the terminal as specified by vtno,
1627  *          which is from 1 to 24.
1628  *
1629  * Here keyid is the keycode of UPARROW, LEFTARROW, or RIGHTARROW
1630  * when it is a kind of arrow key as indicated by is_arrow_key,
1631  * otherwise it indicates a function key and keyid is the number
1632  * corresponding to that function key.
1633  */
1634 static void
1635 kbtrans_vt_compose(struct kbtrans *upper, unsigned short keyid,
1636     boolean_t is_arrow_key, char *buf)
1637 {
1638         char            *bufp;
1639 
1640         bufp = buf;
1641         *bufp++ = '\033'; /* Escape */
1642         *bufp++ = 'Q';
1643         if (is_arrow_key) {
1644                 *bufp++ = 'A';
1645                 switch (keyid) {
1646                 case UPARROW: /* last vt */
1647                         *bufp++ = 'L';
1648                         break;
1649                 case LEFTARROW: /* previous vt */
1650                         *bufp++ = 'B';
1651                         break;
1652                 case RIGHTARROW: /* next vt */
1653                         *bufp++ = 'F';
1654                         break;
1655                 default:
1656                         break;
1657                 }
1658         } else {
1659                 /* this is funckey specifying vtno for switch */
1660                 *bufp++ = keyid +
1661                     (upper->vt_switch_keystate - VT_SWITCH_KEY_ALT) *
1662                     KB_NR_FUNCKEYS + 'A';
1663                 *bufp++ = 'H';
1664         }
1665         *bufp++ = 'z';
1666         *bufp = '\0';
1667 
1668         /*
1669          * Send the result upstream.
1670          */
1671         kbtrans_putbuf(buf, upper->kbtrans_streams_readq);
1672 
1673 }
1674 
1675 /*
1676  * kbtrans_ascii_keypressed:
1677  *      This is the code if we are in TR_ASCII mode and a key
1678  *      is pressed.  This is where we will do any special processing that
1679  *      is specific to ASCII key translation.
1680  */
1681 /* ARGSUSED */
1682 static void
1683 kbtrans_ascii_keypressed(
1684     struct kbtrans      *upper,
1685     uint_t              entrytype,
1686     kbtrans_key_t       key,
1687     uint_t              entry)
1688 {
1689         register char   *cp;
1690         register char   *bufp;
1691         char            buf[14];
1692         unsigned short          keyid;
1693         struct kbtrans_lower    *lower = &upper->kbtrans_lower;
1694 
1695         /*
1696          * Based on the type of key, we may need to do some ASCII
1697          * specific post processing. Note that the translated entry
1698          * is constructed as the actual keycode plus entrytype. see
1699          * sys/kbd.h for details of each entrytype.
1700          */
1701         switch (entrytype) {
1702 
1703         case BUCKYBITS:
1704                 return;
1705 
1706         case SHIFTKEYS:
1707                 keyid = entry & 0xFF;
1708                 if (keyid == ALT) {
1709                         upper->vt_switch_keystate = VT_SWITCH_KEY_ALT;
1710                 } else if (keyid == ALTGRAPH) {
1711                         upper->vt_switch_keystate = VT_SWITCH_KEY_ALTGR;
1712                 }
1713                 return;
1714 
1715         case FUNNY:
1716                 /*
1717                  * There is no ascii equivalent.  We will ignore these
1718                  * keys
1719                  */
1720                 return;
1721 
1722         case FUNCKEYS:
1723                 if (upper->vt_switch_keystate > VT_SWITCH_KEY_NONE) {
1724                         if (entry >= TOPFUNC &&
1725                             entry < (TOPFUNC + KB_NR_FUNCKEYS)) {
1726 
1727                                 /*
1728                                  * keyid is the number correspoding to F#
1729                                  * and its value is from 1 to 12.
1730                                  */
1731                                 keyid = (entry & 0xF) + 1;
1732 
1733                                 kbtrans_vt_compose(upper, keyid, B_FALSE, buf);
1734                                 return;
1735                         }
1736                 }
1737 
1738                 /*
1739                  * We need to expand this key to get the ascii
1740                  * equivalent.  These are the function keys (F1, F2 ...)
1741                  */
1742                 bufp = buf;
1743                 cp = kbtrans_strsetwithdecimal(bufp + 2,
1744                     (uint_t)((entry & 0x003F) + 192),
1745                     sizeof (buf) - 5);
1746                 *bufp++ = '\033'; /* Escape */
1747                 *bufp++ = '[';
1748                 while (*cp != '\0')
1749                         *bufp++ = *cp++;
1750                 *bufp++ = 'z';
1751                 *bufp = '\0';
1752 
1753                 /*
1754                  * Send the result upstream.
1755                  */
1756                 kbtrans_putbuf(buf, upper->kbtrans_streams_readq);
1757 
1758                 return;
1759 
1760         case STRING:
1761                 if (upper->vt_switch_keystate > VT_SWITCH_KEY_NONE) {
1762                         keyid = entry & 0xFF;
1763                         if (keyid == UPARROW ||
1764                             keyid == RIGHTARROW ||
1765                             keyid == LEFTARROW) {
1766 
1767                                 kbtrans_vt_compose(upper, keyid, B_TRUE, buf);
1768                                 return;
1769                         }
1770                 }
1771 
1772                 /*
1773                  * These are the multi byte keys (Home, Up, Down ...)
1774                  */
1775                 cp = &lower->kbtrans_keystringtab[entry & 0x0F][0];
1776 
1777                 /*
1778                  * Copy the string from the keystringtable, and send it
1779                  * upstream a character at a time.
1780                  */
1781                 while (*cp != '\0') {
1782 
1783                         kbtrans_putcode(upper, (uchar_t)*cp);
1784 
1785                         cp++;
1786                 }
1787 
1788                 return;
1789 
1790         case PADKEYS:
1791                 /*
1792                  * These are the keys on the keypad.  Look up the
1793                  * answer in the kb_numlock_table and send it upstream.
1794                  */
1795                 kbtrans_putcode(upper,
1796                     lower->kbtrans_numlock_table[entry&0x1F]);
1797 
1798                 return;
1799 
1800         case 0: /* normal character */
1801         default:
1802                 break;
1803         }
1804 
1805         /*
1806          * Send the char upstream.
1807          */
1808         kbtrans_putcode(upper, entry);
1809 
1810 }
1811 
1812 #define KB_SCANCODE_ALT         0xe2
1813 #define KB_SCANCODE_ALTGRAPH    0xe6
1814 
1815 /*
1816  * kbtrans_ascii_keyreleased:
1817  *      This is the function if we are in TR_ASCII mode and a key
1818  *      is released.  ASCII doesn't have the concept of released keys,
1819  *      or make/break codes.  So there is nothing for us to do except
1820  *      checking 'Alt/AltGraph' release key in order to reset the state
1821  *      of vt switch key sequence.
1822  */
1823 /* ARGSUSED */
1824 static void
1825 kbtrans_ascii_keyreleased(struct kbtrans *upper, kbtrans_key_t key)
1826 {
1827         if (key == KB_SCANCODE_ALT || key == KB_SCANCODE_ALTGRAPH) {
1828                 upper->vt_switch_keystate = VT_SWITCH_KEY_NONE;
1829         }
1830 }
1831 
1832 /*
1833  * kbtrans_ascii_setup_repeat:
1834  *      This is the function if we are in TR_ASCII mode and the
1835  *      translation module has decided that a key needs to be repeated.
1836  */
1837 /* ARGSUSED */
1838 static void
1839 kbtrans_ascii_setup_repeat(
1840     struct kbtrans *upper,
1841     uint_t entrytype,
1842     kbtrans_key_t key)
1843 {
1844         struct kbtrans_lower *lower = &upper->kbtrans_lower;
1845 
1846         /*
1847          * Cancel any currently repeating keys.  This will be a new
1848          * key to repeat.
1849          */
1850         kbtrans_cancelrpt(upper);
1851 
1852         /*
1853          * Set the value of the key to be repeated.
1854          */
1855         lower->kbtrans_repeatkey = key;
1856 
1857         /*
1858          * Start the timeout for repeating this key.  kbtrans_rpt will
1859          * be called to repeat the key.
1860          */
1861         upper->kbtrans_streams_rptid = qtimeout(upper->kbtrans_streams_readq,
1862             kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
1863 }
1864 
1865 /*
1866  * kbtrans_trans_event_keypressed:
1867  *      This is the function if we are in TR_EVENT mode and a key
1868  *      is pressed.  This is where we will do any special processing that
1869  *      is specific to EVENT key translation.
1870  */
1871 static void
1872 kbtrans_trans_event_keypressed(
1873         struct kbtrans  *upper,
1874         uint_t          entrytype,
1875         kbtrans_key_t   key,
1876         uint_t          entry)
1877 {
1878         Firm_event      fe;
1879         register char   *cp;
1880         struct kbtrans_lower    *lower = &upper->kbtrans_lower;
1881 
1882         /*
1883          * Based on the type of key, we may need to do some EVENT
1884          * specific post processing.
1885          */
1886         switch (entrytype) {
1887 
1888         case SHIFTKEYS:
1889                 /*
1890                  * Relying on ordinal correspondence between
1891                  * vuid_event.h SHIFT_META-SHIFT_TOP &
1892                  * kbd.h METABIT-SYSTEMBIT in order to
1893                  * correctly translate entry into fe.id.
1894                  */
1895                 fe.id = SHIFT_CAPSLOCK + (entry & 0x0F);
1896                 fe.value = 1;
1897                 kbtrans_keypressed(upper, key, &fe, fe.id);
1898 
1899                 return;
1900 
1901         case BUCKYBITS:
1902                 /*
1903                  * Relying on ordinal correspondence between
1904                  * vuid_event.h SHIFT_CAPSLOCK-SHIFT_RIGHTCTRL &
1905                  * kbd.h CAPSLOCK-RIGHTCTRL in order to
1906                  * correctly translate entry into fe.id.
1907                  */
1908                 fe.id = SHIFT_META + (entry & 0x0F);
1909                 fe.value = 1;
1910                 kbtrans_keypressed(upper, key, &fe, fe.id);
1911 
1912                 return;
1913 
1914         case FUNCKEYS:
1915                 /*
1916                  * Take advantage of the similar
1917                  * ordering of kbd.h function keys and
1918                  * vuid_event.h function keys to do a
1919                  * simple translation to achieve a
1920                  * mapping between the 2 different
1921                  * address spaces.
1922                  */
1923                 fe.id = KEY_LEFTFIRST + (entry & 0x003F);
1924                 fe.value = 1;
1925 
1926                 /*
1927                  * Assume "up" table only generates
1928                  * shift changes.
1929                  */
1930                 kbtrans_keypressed(upper, key, &fe, fe.id);
1931 
1932                 /*
1933                  * Function key events can be expanded
1934                  * by terminal emulator software to
1935                  * produce the standard escape sequence
1936                  * generated by the TR_ASCII case above
1937                  * if a function key event is not used
1938                  * by terminal emulator software
1939                  * directly.
1940                  */
1941                 return;
1942 
1943         case STRING:
1944                 /*
1945                  * These are the multi byte keys (Home, Up, Down ...)
1946                  */
1947                 cp = &lower->kbtrans_keystringtab[entry & 0x0F][0];
1948 
1949                 /*
1950                  * Copy the string from the keystringtable, and send it
1951                  * upstream a character at a time.
1952                  */
1953                 while (*cp != '\0') {
1954 
1955                         kbtrans_send_esc_event(*cp, upper);
1956 
1957                         cp++;
1958                 }
1959 
1960                 return;
1961 
1962         case PADKEYS:
1963                 /*
1964                  * Take advantage of the similar
1965                  * ordering of kbd.h keypad keys and
1966                  * vuid_event.h keypad keys to do a
1967                  * simple translation to achieve a
1968                  * mapping between the 2 different
1969                  * address spaces.
1970                  */
1971                 fe.id = VKEY_FIRSTPAD + (entry & 0x001F);
1972                 fe.value = 1;
1973 
1974                 /*
1975                  * Assume "up" table only generates
1976                  * shift changes.
1977                  */
1978                 kbtrans_keypressed(upper, key, &fe, fe.id);
1979 
1980                 /*
1981                  * Keypad key events can be expanded
1982                  * by terminal emulator software to
1983                  * produce the standard ascii character
1984                  * generated by the TR_ASCII case above
1985                  * if a keypad key event is not used
1986                  * by terminal emulator software
1987                  * directly.
1988                  */
1989                 return;
1990 
1991         case FUNNY:
1992                 /*
1993                  * These are not events.
1994                  */
1995                 switch (entry) {
1996                 case IDLE:
1997                 case RESET:
1998                 case ERROR:
1999                         /*
2000                          * Something has happened.  Mark all keys as released.
2001                          */
2002                         kbtrans_streams_releaseall(upper);
2003                         break;
2004                 }
2005 
2006                 return;
2007 
2008         case 0: /* normal character */
2009         default:
2010                 break;
2011         }
2012 
2013         /*
2014          * Send the event upstream.
2015          */
2016         fe.id = entry;
2017 
2018         fe.value = 1;
2019 
2020         kbtrans_queueevent(upper, &fe);
2021 }
2022 
2023 /*
2024  * kbtrans_trans_event_keyreleased:
2025  *      This is the function if we are in TR_EVENT mode and a key
2026  *      is released.
2027  */
2028 /* ARGSUSED */
2029 static void
2030 kbtrans_trans_event_keyreleased(struct kbtrans *upper, kbtrans_key_t key)
2031 {
2032         /*
2033          * Mark the key as released and send an event upstream.
2034          */
2035         kbtrans_keyreleased(upper, key);
2036 }
2037 
2038 /*
2039  * kbtrans_trans_event_setup_repeat:
2040  *      This is the function if we are in TR_EVENT mode and the
2041  *      translation module has decided that a key needs to be repeated.
2042  *      We will set a timeout to retranslate the repeat key.
2043  */
2044 static void
2045 kbtrans_trans_event_setup_repeat(
2046         struct kbtrans  *upper,
2047         uint_t          entrytype,
2048         kbtrans_key_t   key)
2049 {
2050         struct kbtrans_lower *lower = &upper->kbtrans_lower;
2051 
2052         /*
2053          * Function keys and keypad keys do not repeat when we are in
2054          * EVENT mode.
2055          */
2056         if (entrytype == FUNCKEYS || entrytype == PADKEYS) {
2057 
2058                 return;
2059         }
2060 
2061         /*
2062          * Cancel any currently repeating keys.  This will be a new
2063          * key to repeat.
2064          */
2065         kbtrans_cancelrpt(upper);
2066 
2067         /*
2068          * Set the value of the key to be repeated.
2069          */
2070         lower->kbtrans_repeatkey = key;
2071 
2072         /*
2073          * Start the timeout for repeating this key.  kbtrans_rpt will
2074          * be called to repeat the key.
2075          */
2076         upper->kbtrans_streams_rptid = qtimeout(upper->kbtrans_streams_readq,
2077             kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
2078 }
2079 
2080 /*
2081  * Administer the key tables.
2082  */
2083 
2084 /*
2085  * Old special codes.
2086  */
2087 #define OLD_SHIFTKEYS   0x80
2088 #define OLD_BUCKYBITS   0x90
2089 #define OLD_FUNNY       0xA0
2090 #define OLD_FA_UMLAUT   0xA9
2091 #define OLD_FA_CFLEX    0xAA
2092 #define OLD_FA_TILDE    0xAB
2093 #define OLD_FA_CEDILLA  0xAC
2094 #define OLD_FA_ACUTE    0xAD
2095 #define OLD_FA_GRAVE    0xAE
2096 #define OLD_ISOCHAR     0xAF
2097 #define OLD_STRING      0xB0
2098 #define OLD_LEFTFUNC    0xC0
2099 #define OLD_RIGHTFUNC   0xD0
2100 #define OLD_TOPFUNC     0xE0
2101 #define OLD_BOTTOMFUNC  0xF0
2102 
2103 /*
2104  * Map old special codes to new ones.
2105  * Indexed by ((old special code) >> 4) & 0x07; add (old special code) & 0x0F.
2106  */
2107 static keymap_entry_t  special_old_to_new[] = {
2108         SHIFTKEYS,
2109         BUCKYBITS,
2110         FUNNY,
2111         STRING,
2112         LEFTFUNC,
2113         RIGHTFUNC,
2114         TOPFUNC,
2115         BOTTOMFUNC,
2116 };
2117 
2118 
2119 /*
2120  * kbtrans_setkey:
2121  *       Set individual keystation translation from old-style entry.
2122  */
2123 static int
2124 kbtrans_setkey(struct kbtrans_lower *lower, struct kiockey *key, cred_t *cr)
2125 {
2126         int     strtabindex, i;
2127         keymap_entry_t  *ke;
2128         register int tablemask;
2129         register keymap_entry_t entry;
2130         register struct keyboard *kp;
2131 
2132         kp = lower->kbtrans_keyboard;
2133 
2134         if (key->kio_station >= kp->k_keymap_size)
2135                 return (EINVAL);
2136 
2137         if (lower->kbtrans_keyboard == NULL)
2138 
2139                 return (EINVAL);
2140 
2141         tablemask = key->kio_tablemask;
2142 
2143         switch (tablemask) {
2144         case KIOCABORT1:
2145         case KIOCABORT1A:
2146         case KIOCABORT2:
2147                 i = secpolicy_console(cr);
2148                 if (i != 0)
2149                         return (i);
2150 
2151                 switch (tablemask) {
2152                 case KIOCABORT1:
2153                         kp->k_abort1 = key->kio_station;
2154                         break;
2155                 case KIOCABORT1A:
2156                         kp->k_abort1a = key->kio_station;
2157                         break;
2158                 case KIOCABORT2:
2159                         kp->k_abort2 = key->kio_station;
2160                         break;
2161                 }
2162                 return (0);
2163         }
2164 
2165         if (tablemask & ALTGRAPHMASK)
2166                 return (EINVAL);
2167 
2168         ke = kbtrans_find_entry(lower, (uint_t)tablemask, key->kio_station);
2169         if (ke == NULL)
2170                 return (EINVAL);
2171 
2172         if (key->kio_entry >= (uchar_t)OLD_STRING &&
2173             key->kio_entry <= (uchar_t)(OLD_STRING + 15)) {
2174                 strtabindex = key->kio_entry - OLD_STRING;
2175                 bcopy(key->kio_string,
2176                     lower->kbtrans_keystringtab[strtabindex], KTAB_STRLEN);
2177                 lower->kbtrans_keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
2178         }
2179 
2180         entry = key->kio_entry;
2181 
2182         /*
2183          * There's nothing we need do with OLD_ISOCHAR.
2184          */
2185         if (entry != OLD_ISOCHAR) {
2186                 if (entry & 0x80) {
2187                         if (entry >= OLD_FA_UMLAUT && entry <= OLD_FA_GRAVE)
2188                                 entry = FA_CLASS + (entry & 0x0F) - 9;
2189                         else
2190                                 entry =
2191                                     special_old_to_new[entry >> 4 & 0x07]
2192                                     + (entry & 0x0F);
2193                 }
2194         }
2195 
2196         *ke = entry;
2197 
2198         return (0);
2199 }
2200 
2201 
2202 /*
2203  * Map new special codes to old ones.
2204  * Indexed by (new special code) >> 8; add (new special code) & 0xFF.
2205  */
2206 static uchar_t   special_new_to_old[] = {
2207         0,                      /* normal */
2208         OLD_SHIFTKEYS,          /* SHIFTKEYS */
2209         OLD_BUCKYBITS,          /* BUCKYBITS */
2210         OLD_FUNNY,              /* FUNNY */
2211         OLD_FA_UMLAUT,          /* FA_CLASS */
2212         OLD_STRING,             /* STRING */
2213         OLD_LEFTFUNC,           /* FUNCKEYS */
2214 };
2215 
2216 
2217 /*
2218  * kbtrans_getkey:
2219  *      Get individual keystation translation as old-style entry.
2220  */
2221 static int
2222 kbtrans_getkey(struct kbtrans_lower *lower, struct kiockey *key)
2223 {
2224         int     strtabindex;
2225         keymap_entry_t  *ke;
2226         register keymap_entry_t entry;
2227         struct keyboard *kp;
2228 
2229         kp = lower->kbtrans_keyboard;
2230 
2231         if (key->kio_station >= kp->k_keymap_size)
2232                 return (EINVAL);
2233 
2234         if (lower->kbtrans_keyboard == NULL)
2235                 return (EINVAL);
2236 
2237         switch (key->kio_tablemask) {
2238         case KIOCABORT1:
2239                 key->kio_station = kp->k_abort1;
2240                 return (0);
2241         case KIOCABORT1A:
2242                 key->kio_station = kp->k_abort1a;
2243                 return (0);
2244         case KIOCABORT2:
2245                 key->kio_station = kp->k_abort2;
2246                 return (0);
2247         }
2248 
2249         ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2250             key->kio_station);
2251         if (ke == NULL)
2252                 return (EINVAL);
2253 
2254         entry = *ke;
2255 
2256         if (entry & 0xFF00)
2257                 key->kio_entry =
2258                     special_new_to_old[(ushort_t)(entry & 0xFF00) >> 8]
2259                     + (entry & 0x00FF);
2260         else {
2261                 if (entry & 0x80)
2262                         key->kio_entry = (ushort_t)OLD_ISOCHAR;      /* you lose */
2263                 else
2264                         key->kio_entry = (ushort_t)entry;
2265         }
2266 
2267         if (entry >= STRING && entry <= (uchar_t)(STRING + 15)) {
2268                 strtabindex = entry - STRING;
2269                 bcopy(lower->kbtrans_keystringtab[strtabindex],
2270                     key->kio_string, KTAB_STRLEN);
2271         }
2272         return (0);
2273 }
2274 
2275 
2276 /*
2277  * kbtrans_skey:
2278  *      Set individual keystation translation from new-style entry.
2279  */
2280 static int
2281 kbtrans_skey(struct kbtrans_lower *lower, struct kiockeymap *key, cred_t *cr)
2282 {
2283         int     strtabindex, i;
2284         keymap_entry_t *ke;
2285         struct keyboard *kp;
2286 
2287         kp = lower->kbtrans_keyboard;
2288 
2289         if (key->kio_station >= kp->k_keymap_size) {
2290                 return (EINVAL);
2291 
2292         }
2293 
2294         if (lower->kbtrans_keyboard == NULL) {
2295                 return (EINVAL);
2296         }
2297 
2298         switch (key->kio_tablemask) {
2299         case KIOCABORT1:
2300         case KIOCABORT1A:
2301         case KIOCABORT2:
2302                 i = secpolicy_console(cr);
2303                 if (i != 0)
2304                         return (i);
2305                 switch (key->kio_tablemask) {
2306                 case KIOCABORT1:
2307                         kp->k_abort1 = key->kio_station;
2308                         break;
2309                 case KIOCABORT1A:
2310                         kp->k_abort1a = key->kio_station;
2311                         break;
2312                 case KIOCABORT2:
2313                         kp->k_abort2 = key->kio_station;
2314                         break;
2315                 }
2316                 return (0);
2317         }
2318 
2319         ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2320             key->kio_station);
2321         if (ke == NULL)
2322                 return (EINVAL);
2323 
2324         if (key->kio_entry >= STRING &&
2325             key->kio_entry <= (STRING + 15)) {
2326                 strtabindex = key->kio_entry-STRING;
2327                 bcopy(key->kio_string,
2328                     lower->kbtrans_keystringtab[strtabindex], KTAB_STRLEN);
2329                 lower->kbtrans_keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
2330         }
2331 
2332         *ke = key->kio_entry;
2333 
2334         return (0);
2335 }
2336 
2337 
2338 /*
2339  * kbtrans_gkey:
2340  *      Get individual keystation translation as new-style entry.
2341  */
2342 static int
2343 kbtrans_gkey(struct kbtrans_lower *lower, struct kiockeymap *key)
2344 {
2345         int     strtabindex;
2346         keymap_entry_t *ke;
2347         struct keyboard *kp;
2348 
2349         kp = lower->kbtrans_keyboard;
2350 
2351         if (key->kio_station >= kp->k_keymap_size)
2352                 return (EINVAL);
2353 
2354         if (lower->kbtrans_keyboard == NULL)
2355                 return (EINVAL);
2356 
2357         switch (key->kio_tablemask) {
2358         case KIOCABORT1:
2359                 key->kio_station = kp->k_abort1;
2360                 return (0);
2361         case KIOCABORT1A:
2362                 key->kio_station = kp->k_abort1a;
2363                 return (0);
2364         case KIOCABORT2:
2365                 key->kio_station = kp->k_abort2;
2366                 return (0);
2367         }
2368 
2369         ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2370             key->kio_station);
2371         if (ke == NULL)
2372                 return (EINVAL);
2373 
2374         key->kio_entry = *ke;
2375 
2376         if (key->kio_entry >= STRING &&
2377             key->kio_entry <= (STRING + 15)) {
2378                 strtabindex = key->kio_entry-STRING;
2379                 bcopy(lower->kbtrans_keystringtab[strtabindex],
2380                     key->kio_string, KTAB_STRLEN);
2381         }
2382         return (0);
2383 }