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