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