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