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