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