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