Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / kbtrans / kbtrans_streams.c
blob8e3f4a9d7920c7315779bdae1a1ee8dbc751d352
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Generic keyboard support: streams and administration.
31 #define KEYMAP_SIZE_VARIABLE
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"
55 #ifdef DEBUG
56 int kbtrans_errmask;
57 int kbtrans_errlevel;
58 #endif
60 #define KB_NR_FUNCKEYS 12
63 * Repeat rates set in static variables so they can be tweeked with
64 * debugger.
66 static int kbtrans_repeat_rate;
67 static int kbtrans_repeat_delay;
69 /* Printing message on q overflow */
70 static int kbtrans_overflow_msg = 1;
73 * This value corresponds approximately to max 10 fingers
75 static int kbtrans_downs_size = 15;
78 * modload support
80 extern struct mod_ops mod_miscops;
82 static struct modlmisc modlmisc = {
83 &mod_miscops, /* Type of module */
84 "kbtrans (key translation)"
87 static struct modlinkage modlinkage = {
88 MODREV_1, (void *)&modlmisc, NULL
91 int
92 _init(void)
94 return (mod_install(&modlinkage));
97 int
98 _fini(void)
100 return (mod_remove(&modlinkage));
104 _info(struct modinfo *modinfop)
106 return (mod_info(&modlinkage, modinfop));
110 * Internal Function Prototypes
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 *);
151 * Keyboard Translation Mode (TR_NONE)
153 * Functions to be called when keyboard translation is turned off
154 * and up/down key codes are reported.
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,
167 * Keyboard Translation Mode (TR_ASCII)
169 * Functions to be called when ISO 8859/1 codes are reported
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,
182 * Keyboard Translation Mode (TR_EVENT)
184 * Functions to be called when firm_events are reported.
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,
196 static void
197 progressbar_key_abort_thread(struct kbtrans *upper)
199 ldi_ident_t li;
200 extern void progressbar_key_abort(ldi_ident_t);
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);
215 ldi_ident_release(li);
218 thread_exit();
222 * kbtrans_streams_init:
223 * Initialize the stream, keytables, callbacks, etc.
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)
235 struct kbtrans *upper;
236 struct kbtrans_lower *lower;
237 kthread_t *tid;
240 * Default to relatively generic tables.
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[];
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;
254 switch (sflag) {
256 case MODOPEN:
257 break;
259 case CLONEOPEN:
260 DPRINTF(PRINT_L1, PRINT_MASK_OPEN, (NULL,
261 "kbtrans_streams_init: Clone open not supported"));
263 return (EINVAL);
266 /* allocate keyboard state structure */
267 upper = kmem_zalloc(sizeof (struct kbtrans), KM_SLEEP);
269 *ret_kbd = upper;
271 upper->kbtrans_polled_buf[0] = '\0';
272 upper->kbtrans_polled_pending_chars = upper->kbtrans_polled_buf;
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;
282 /* Set the translation callback based on the translation type */
283 kbtrans_set_translation_callback(upper);
285 lower = &upper->kbtrans_lower;
288 * Set defaults for relatively generic tables.
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;
296 lower->kbtrans_upper = upper;
297 lower->kbtrans_compat = 1;
300 * We have a generic default for the LED state, and let the
301 * hardware-specific driver supply overrides.
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;
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;
313 #if defined(SCROLLMASK)
314 if (lower->kbtrans_led_state & LED_SCROLL_LOCK)
315 lower->kbtrans_togglemask |= SCROLLMASK;
316 #endif
318 lower->kbtrans_shiftmask = lower->kbtrans_togglemask;
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;
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;
332 upper->kbtrans_streams_flags = KBTRANS_STREAMS_OPEN;
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;
343 DPRINTF(PRINT_L1, PRINT_MASK_OPEN, (upper, "kbtrans_streams_init "
344 "exiting"));
345 return (0);
350 * kbtrans_streams_fini:
351 * Free structures and uninitialize the stream
354 kbtrans_streams_fini(struct kbtrans *upper)
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.
361 upper->kbtrans_streams_flags = 0;
363 /* clear all timeouts */
364 if (upper->kbtrans_streams_bufcallid) {
365 qunbufcall(upper->kbtrans_streams_readq,
366 upper->kbtrans_streams_bufcallid);
368 if (upper->kbtrans_streams_rptid) {
369 (void) quntimeout(upper->kbtrans_streams_readq,
370 upper->kbtrans_streams_rptid);
372 kmem_free(upper->kbtrans_streams_downs,
373 upper->kbtrans_streams_downs_bytes);
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);
384 cv_destroy(&upper->progressbar_key_abort_cv);
385 mutex_destroy(&upper->progressbar_key_abort_lock);
387 kmem_free(upper, sizeof (struct kbtrans));
389 DPRINTF(PRINT_L1, PRINT_MASK_CLOSE, (upper, "kbtrans_streams_fini "
390 "exiting"));
391 return (0);
395 * kbtrans_streams_releaseall :
396 * This function releases all the held keys.
398 void
399 kbtrans_streams_releaseall(struct kbtrans *upper)
401 register struct key_event *ke;
402 register int i;
404 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL, "USBKBM RELEASE ALL\n"));
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++) {
410 /* Key station not zero */
411 if (ke->key_station) {
413 kbtrans_keyreleased(upper, ke->key_station);
414 /* kbtrans_keyreleased resets downs entry */
420 * kbtrans_streams_message:
421 * keyboard module output queue put procedure: handles M_IOCTL
422 * messages.
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.
430 enum kbtrans_message_response
431 kbtrans_streams_message(struct kbtrans *upper, register mblk_t *mp)
433 queue_t *q = upper->kbtrans_streams_readq;
434 enum kbtrans_message_response ret;
436 DPRINTF(PRINT_L1, PRINT_MASK_ALL, (upper,
437 "kbtrans_streams_message entering"));
439 * Process M_FLUSH, and some M_IOCTL, messages here; pass
440 * everything else down.
442 switch (mp->b_datap->db_type) {
444 case M_IOCTL:
445 ret = kbtrans_ioctl(upper, mp);
446 break;
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);
454 * White lie: we say we didn't handle the message,
455 * so that it gets handled by our client.
457 ret = KBTRANS_MESSAGE_NOT_HANDLED;
458 break;
460 default:
461 ret = KBTRANS_MESSAGE_NOT_HANDLED;
462 break;
465 DPRINTF(PRINT_L1, PRINT_MASK_ALL, (upper,
466 "kbtrans_streams_message exiting\n"));
468 return (ret);
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.
479 void
480 kbtrans_streams_key(
481 struct kbtrans *upper,
482 kbtrans_key_t key,
483 enum keystate state)
485 struct kbtrans_lower *lower;
486 struct keyboard *kp;
488 lower = &upper->kbtrans_lower;
489 kp = lower->kbtrans_keyboard;
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);
497 mutex_exit(&upper->progressbar_key_abort_lock);
499 if (upper->kbtrans_streams_abortable) {
500 switch (upper->kbtrans_streams_abort_state) {
501 case ABORT_NORMAL:
502 if (state != KEY_PRESSED)
503 break;
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;
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;
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(NULL);
525 return;
526 } else {
527 kbtrans_processkey(lower,
528 upper->kbtrans_streams_callback,
529 upper->kbtrans_streams_abort1_key,
530 KEY_PRESSED);
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(NULL);
538 kbtrans_processkey(lower,
539 upper->kbtrans_streams_callback,
540 upper->kbtrans_streams_new_abort1_key,
541 KEY_RELEASED);
542 return;
547 kbtrans_processkey(lower, upper->kbtrans_streams_callback, key, state);
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.
557 void
558 kbtrans_streams_set_keyboard(
559 struct kbtrans *upper,
560 int id,
561 struct keyboard *k)
563 upper->kbtrans_lower.kbtrans_keyboard = k;
564 upper->kbtrans_streams_id = id;
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.
573 /*ARGSUSED*/
574 void
575 kbtrans_streams_has_reset(struct kbtrans *upper)
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.
585 * kbtrans_streams_enable:
586 * This is the routine that is called back when the the stream is ready
587 * to take messages.
589 void
590 kbtrans_streams_enable(struct kbtrans *upper)
592 /* Set the LED's */
593 kbtrans_setled(upper);
597 * kbtrans_streams_setled():
598 * This is the routine that is called to only update the led state
599 * in kbtrans.
601 void
602 kbtrans_streams_setled(struct kbtrans *upper, int led_state)
604 struct kbtrans_lower *lower;
606 lower = &upper->kbtrans_lower;
607 lower->kbtrans_led_state = (uchar_t)led_state;
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;
614 #if defined(SCROLLMASK)
615 if (lower->kbtrans_led_state & LED_SCROLL_LOCK)
616 lower->kbtrans_togglemask |= SCROLLMASK;
617 #endif
619 lower->kbtrans_shiftmask = lower->kbtrans_togglemask;
624 * kbtrans_streams_set_queue:
625 * Set the overlying queue, to support multiplexors.
627 void
628 kbtrans_streams_set_queue(struct kbtrans *upper, queue_t *q)
631 upper->kbtrans_streams_readq = q;
635 * kbtrans_streams_get_queue:
636 * Return the overlying queue.
638 queue_t *
639 kbtrans_streams_get_queue(struct kbtrans *upper)
641 return (upper->kbtrans_streams_readq);
645 * kbtrans_streams_untimeout
646 * Cancell all timeout
648 void
649 kbtrans_streams_untimeout(struct kbtrans *upper)
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;
657 if (upper->kbtrans_streams_rptid) {
658 (void) quntimeout(upper->kbtrans_streams_readq,
659 upper->kbtrans_streams_rptid);
660 upper->kbtrans_streams_rptid = 0;
665 * kbtrans_reioctl:
666 * This function is set up as call-back function should an ioctl fail
667 * to allocate required resources.
669 static void
670 kbtrans_reioctl(void *arg)
672 struct kbtrans *upper = (struct kbtrans *)arg;
673 mblk_t *mp;
675 upper->kbtrans_streams_bufcallid = 0;
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);
685 * kbtrans_ioctl:
686 * process ioctls we recognize and own. Otherwise, pass it down.
688 static enum kbtrans_message_response
689 kbtrans_ioctl(struct kbtrans *upper, register mblk_t *mp)
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;
701 static int kiocgetkey, kiocsetkey;
703 lower = &upper->kbtrans_lower;
705 iocp = (struct iocblk *)mp->b_rptr;
707 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper,
708 "kbtrans_ioctl: ioc_cmd 0x%x - ", iocp->ioc_cmd));
709 switch (iocp->ioc_cmd) {
711 case VUIDSFORMAT:
712 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDSFORMAT\n"));
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;
720 if (new_translate == upper->kbtrans_streams_translate_mode)
721 break;
722 upper->kbtrans_streams_translate_mode = new_translate;
724 kbtrans_set_translation_callback(upper);
726 kbtrans_flush(upper);
727 break;
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);
740 kbtrans_flush(upper);
741 break;
743 case KIOCSLED:
744 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSLED\n"));
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;
751 kbtrans_setled(upper);
752 break;
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;
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;
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;
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;
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;
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;
800 case VUIDSADDR:
801 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDSADDR\n"));
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) {
809 case ASCII_FIRST:
810 addr_ptr = &upper->kbtrans_streams_vuid_addr.ascii;
811 break;
813 case TOP_FIRST:
814 addr_ptr = &upper->kbtrans_streams_vuid_addr.top;
815 break;
817 case VKEY_FIRST:
818 addr_ptr = &upper->kbtrans_streams_vuid_addr.vkey;
819 break;
821 default:
822 err = ENODEV;
825 if ((err == 0) && (*addr_ptr != addr_probe->data.next)) {
826 *addr_ptr = addr_probe->data.next;
827 kbtrans_flush(upper);
829 break;
831 case VUIDGADDR:
832 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDGADDR\n"));
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) {
840 case ASCII_FIRST:
841 addr_probe->data.current =
842 upper->kbtrans_streams_vuid_addr.ascii;
843 break;
845 case TOP_FIRST:
846 addr_probe->data.current =
847 upper->kbtrans_streams_vuid_addr.top;
848 break;
850 case VKEY_FIRST:
851 addr_probe->data.current =
852 upper->kbtrans_streams_vuid_addr.vkey;
853 break;
855 default:
856 err = ENODEV;
858 break;
860 case KIOCTRANSABLE:
861 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCTRANSABLE\n"));
863 err = miocpullup(mp, sizeof (int));
864 if (err != 0)
865 break;
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.
871 translate = *(int *)mp->b_cont->b_rptr;
872 if (upper->kbtrans_streams_translatable != translate)
873 upper->kbtrans_streams_translatable = translate;
875 if (translate != TR_CAN)
876 DPRINTF(PRINT_L4, PRINT_MASK_ALL, (upper,
877 "Cannot translate keyboard using tables.\n"));
878 break;
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;
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;
894 case KIOCSCOMPAT:
895 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSCOMPAT\n"));
897 err = miocpullup(mp, sizeof (int));
898 if (err != 0)
899 break;
900 lower->kbtrans_compat = *(int *)mp->b_cont->b_rptr;
901 break;
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;
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;
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);
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.
930 break;
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;
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);
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.
953 break;
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;
963 case KIOCSDIRECT:
964 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSDIRECT\n"));
965 kbtrans_flush(upper);
966 break;
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;
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;
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;
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;
996 case CONSSETABORTENABLE:
998 * Peek as it goes by; must be a TRANSPARENT ioctl.
1000 if (iocp->ioc_count != TRANSPARENT) {
1001 err = EINVAL;
1002 break;
1005 upper->kbtrans_streams_abortable =
1006 (boolean_t)*(intptr_t *)mp->b_cont->b_rptr;
1009 * Let the hardware module see it too.
1011 return (KBTRANS_MESSAGE_NOT_HANDLED);
1013 case KIOCGRPTDELAY:
1015 * Report the autorepeat delay, unit in millisecond
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;
1022 *(int *)datap->b_wptr = TICK_TO_MSEC(kbtrans_repeat_delay);
1023 datap->b_wptr += sizeof (int);
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;
1032 case KIOCSRPTDELAY:
1034 * Set the autorepeat delay
1036 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSRPTDELAY\n"));
1037 err = miocpullup(mp, sizeof (int));
1039 if (err != 0)
1040 break;
1042 /* validate the input */
1043 if (*(int *)mp->b_cont->b_rptr < KIOCRPTDELAY_MIN) {
1044 err = EINVAL;
1045 break;
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;
1052 case KIOCGRPTRATE:
1054 * Report the autorepeat rate
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;
1061 *(int *)datap->b_wptr = TICK_TO_MSEC(kbtrans_repeat_rate);
1062 datap->b_wptr += sizeof (int);
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;
1071 case KIOCSRPTRATE:
1073 * Set the autorepeat rate
1075 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSRPTRATE\n"));
1076 err = miocpullup(mp, sizeof (int));
1078 if (err != 0)
1079 break;
1081 /* validate the input */
1082 if (*(int *)mp->b_cont->b_rptr < KIOCRPTRATE_MIN) {
1083 err = EINVAL;
1084 break;
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;
1091 default:
1092 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "unknown\n"));
1093 return (KBTRANS_MESSAGE_NOT_HANDLED);
1094 } /* end switch */
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;
1105 putnext(upper->kbtrans_streams_readq, mp);
1107 return (KBTRANS_MESSAGE_HANDLED);
1109 allocfailure:
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.
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);
1124 upper->kbtrans_streams_bufcallid =
1125 qbufcall(upper->kbtrans_streams_readq, ioctlrespsize, BPRI_HI,
1126 kbtrans_reioctl, upper);
1128 * This is a white lie... we *will* handle it, eventually.
1130 return (KBTRANS_MESSAGE_HANDLED);
1134 * kbtrans_flush:
1135 * Flush data upstream
1137 static void
1138 kbtrans_flush(register struct kbtrans *upper)
1140 register queue_t *q;
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);
1146 /* Flush pending ups */
1147 bzero(upper->kbtrans_streams_downs, upper->kbtrans_streams_downs_bytes);
1149 kbtrans_cancelrpt(upper);
1153 * kbtrans_setled:
1154 * Update the keyboard LEDs to match the current keyboard state.
1156 static void
1157 kbtrans_setled(struct kbtrans *upper)
1159 upper->kbtrans_streams_hw_callbacks->kbtrans_streams_setled(
1160 upper->kbtrans_streams_hw,
1161 upper->kbtrans_lower.kbtrans_led_state);
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.
1169 static void
1170 kbtrans_rpt(void *arg)
1172 struct kbtrans *upper = arg;
1173 struct kbtrans_lower *lower = &upper->kbtrans_lower;
1175 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL,
1176 "kbtrans_rpt: repeat key %X\n",
1177 lower->kbtrans_repeatkey));
1179 upper->kbtrans_streams_rptid = 0;
1182 * NB: polled code zaps kbtrans_repeatkey without cancelling
1183 * timeout.
1185 if (lower->kbtrans_repeatkey != 0) {
1186 kbtrans_keyreleased(upper, lower->kbtrans_repeatkey);
1188 kbtrans_processkey(lower,
1189 upper->kbtrans_streams_callback,
1190 lower->kbtrans_repeatkey,
1191 KEY_PRESSED);
1193 upper->kbtrans_streams_rptid =
1194 qtimeout(upper->kbtrans_streams_readq, kbtrans_rpt,
1195 (caddr_t)upper, kbtrans_repeat_rate);
1200 * kbtrans_cancelrpt:
1201 * Cancel the repeating key
1203 static void
1204 kbtrans_cancelrpt(struct kbtrans *upper)
1206 upper->kbtrans_lower.kbtrans_repeatkey = 0;
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;
1216 * kbtrans_send_esc_event:
1217 * Send character up stream. Used for the case of
1218 * sending strings upstream.
1220 static void
1221 kbtrans_send_esc_event(char c, register struct kbtrans *upper)
1223 Firm_event fe;
1225 fe.id = c;
1226 fe.value = 1;
1227 fe.pair_type = FE_PAIR_NONE;
1228 fe.pair = 0;
1230 * Pretend as if each cp pushed and released
1231 * Calling kbtrans_queueevent avoids addr translation
1232 * and pair base determination of kbtrans_keypressed.
1234 kbtrans_queueevent(upper, &fe);
1235 fe.value = 0;
1236 kbtrans_queueevent(upper, &fe);
1240 * kbtrans_strsetwithdecimal:
1241 * Used for expanding a function key to the ascii equivalent
1243 static char *
1244 kbtrans_strsetwithdecimal(char *buf, uint_t val, uint_t maxdigs)
1246 int hradix = 5;
1247 char *bp;
1248 int lowbit;
1249 char *tab = "0123456789abcdef";
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;
1259 return (bp);
1263 * kbtrans_keypressed:
1264 * Modify Firm event to be sent up the stream
1266 static void
1267 kbtrans_keypressed(struct kbtrans *upper, uchar_t key_station,
1268 Firm_event *fe, ushort_t base)
1271 register short id_addr;
1272 struct kbtrans_lower *lower = &upper->kbtrans_lower;
1274 /* Set pair values */
1275 if (fe->id < (ushort_t)VKEY_FIRST) {
1277 * If CTRLed, find the ID that would have been used had it
1278 * not been CTRLed.
1280 if (lower->kbtrans_shiftmask & (CTRLMASK | CTLSMASK)) {
1281 keymap_entry_t *ke;
1282 unsigned int mask;
1284 mask = lower->kbtrans_shiftmask &
1285 ~(CTRLMASK | CTLSMASK | UPMASK);
1287 ke = kbtrans_find_entry(lower, mask, key_station);
1288 if (ke == NULL)
1289 return;
1291 base = *ke;
1293 if (base != fe->id) {
1294 fe->pair_type = FE_PAIR_SET;
1295 fe->pair = (uchar_t)base;
1297 goto send;
1300 fe->pair_type = FE_PAIR_NONE;
1301 fe->pair = 0;
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;
1319 fe->id = vuid_id_offset(fe->id) | id_addr;
1321 kbtrans_queuepress(upper, key_station, fe);
1325 * kbtrans_queuepress:
1326 * Add keypress to the "downs" table
1328 static void
1329 kbtrans_queuepress(struct kbtrans *upper,
1330 uchar_t key_station, Firm_event *fe)
1332 register struct key_event *ke, *ke_free;
1333 register int i;
1335 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL, "kbtrans_queuepress:"
1336 " key=%d", key_station));
1338 ke_free = 0;
1340 /* Scan table of down key stations */
1342 for (i = 0, ke = upper->kbtrans_streams_downs;
1343 i < upper->kbtrans_streams_num_downs_entries; i++, ke++) {
1345 /* Keycode already down? */
1346 if (ke->key_station == key_station) {
1348 DPRINTF(PRINT_L0, PRINT_MASK_ALL,
1349 (NULL, "kbtrans: Double "
1350 "entry in downs table (%d,%d)!\n",
1351 key_station, i));
1353 goto add_event;
1356 if (ke->key_station == 0)
1357 ke_free = ke;
1360 if (ke_free) {
1361 ke = ke_free;
1362 goto add_event;
1365 ke = upper->kbtrans_streams_downs;
1367 add_event:
1368 ke->key_station = key_station;
1369 ke->event = *fe;
1370 kbtrans_queueevent(upper, fe);
1374 * kbtrans_keyreleased:
1375 * Remove entry from the downs table
1377 static void
1378 kbtrans_keyreleased(register struct kbtrans *upper, uchar_t key_station)
1380 register struct key_event *ke;
1381 register int i;
1383 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL, "RELEASE key=%d\n",
1384 key_station));
1386 if (upper->kbtrans_streams_translate_mode != TR_EVENT &&
1387 upper->kbtrans_streams_translate_mode != TR_UNTRANS_EVENT) {
1389 return;
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);
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.
1413 * kbtrans_putcode:
1414 * Pass a keycode up the stream, if you can, otherwise throw it away.
1416 static void
1417 kbtrans_putcode(register struct kbtrans *upper, uint_t code)
1419 register mblk_t *bp;
1422 * If we can't send it up, then we just drop it.
1424 if (!canputnext(upper->kbtrans_streams_readq)) {
1426 return;
1430 * Allocate a messsage block to send up.
1432 if ((bp = allocb(sizeof (uint_t), BPRI_HI)) == NULL) {
1434 cmn_err(CE_WARN, "kbtrans_putcode: Can't allocate block\
1435 for keycode.");
1437 return;
1441 * We will strip out any high order information here.
1442 * Convert to UTF-8.
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);
1462 * Send the message up.
1464 (void) putnext(upper->kbtrans_streams_readq, bp);
1469 * kbtrans_putbuf:
1470 * Pass generated keycode sequence to upstream, if possible.
1472 static void
1473 kbtrans_putbuf(char *buf, queue_t *q)
1475 register mblk_t *bp;
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++;
1488 putnext(q, bp);
1494 * kbtrans_queueevent:
1495 * Pass a VUID "firm event" up the stream, if you can.
1497 static void
1498 kbtrans_queueevent(struct kbtrans *upper, Firm_event *fe)
1500 register queue_t *q;
1501 register mblk_t *bp;
1503 if ((q = upper->kbtrans_streams_readq) == NULL)
1505 return;
1507 if (!canputnext(q)) {
1508 if (kbtrans_overflow_msg) {
1509 DPRINTF(PRINT_L2, PRINT_MASK_ALL, (NULL,
1510 "kbtrans: Buffer flushed when overflowed."));
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);
1531 * kbtrans_set_translation_callback:
1532 * This code sets the translation_callback pointer based on the
1533 * translation mode.
1535 static void
1536 kbtrans_set_translation_callback(register struct kbtrans *upper)
1538 switch (upper->kbtrans_streams_translate_mode) {
1540 default:
1541 case TR_ASCII:
1542 upper->vt_switch_keystate = VT_SWITCH_KEY_NONE;
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);
1550 upper->kbtrans_streams_callback = &ascii_callback;
1552 break;
1554 case TR_EVENT:
1555 upper->kbtrans_streams_callback = &trans_event_callback;
1557 break;
1559 case TR_UNTRANS_EVENT:
1560 upper->kbtrans_streams_callback = &untrans_event_callback;
1562 break;
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.
1572 static void
1573 kbtrans_untrans_keypressed_raw(struct kbtrans *upper, kbtrans_key_t key)
1575 Firm_event fe;
1577 bzero(&fe, sizeof (fe));
1580 * fill in the event
1582 fe.id = (unsigned short)key;
1583 fe.value = 1;
1586 * Send the event upstream.
1588 kbtrans_queuepress(upper, key, &fe);
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.
1597 static void
1598 kbtrans_untrans_keyreleased_raw(struct kbtrans *upper, kbtrans_key_t key)
1601 * Deal with a key released event.
1603 kbtrans_keyreleased(upper, key);
1607 * kbtrans_vt_compose:
1608 * To compose the key sequences for virtual terminal switching.
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
1616 * the vt switching message is encoded as:
1618 * -------------------------------------------------------------
1619 * | \033 | 'Q' | vtno + 'A' | opcode | 'z' | '\0' |
1620 * -------------------------------------------------------------
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.
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.
1634 static void
1635 kbtrans_vt_compose(struct kbtrans *upper, unsigned short keyid,
1636 boolean_t is_arrow_key, char *buf)
1638 char *bufp;
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;
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';
1665 *bufp++ = 'z';
1666 *bufp = '\0';
1669 * Send the result upstream.
1671 kbtrans_putbuf(buf, upper->kbtrans_streams_readq);
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.
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)
1689 register char *cp;
1690 register char *bufp;
1691 char buf[14];
1692 unsigned short keyid;
1693 struct kbtrans_lower *lower = &upper->kbtrans_lower;
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.
1701 switch (entrytype) {
1703 case BUCKYBITS:
1704 return;
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;
1713 return;
1715 case FUNNY:
1717 * There is no ascii equivalent. We will ignore these
1718 * keys
1720 return;
1722 case FUNCKEYS:
1723 if (upper->vt_switch_keystate > VT_SWITCH_KEY_NONE) {
1724 if (entry >= TOPFUNC &&
1725 entry < (TOPFUNC + KB_NR_FUNCKEYS)) {
1728 * keyid is the number correspoding to F#
1729 * and its value is from 1 to 12.
1731 keyid = (entry & 0xF) + 1;
1733 kbtrans_vt_compose(upper, keyid, B_FALSE, buf);
1734 return;
1739 * We need to expand this key to get the ascii
1740 * equivalent. These are the function keys (F1, F2 ...)
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';
1754 * Send the result upstream.
1756 kbtrans_putbuf(buf, upper->kbtrans_streams_readq);
1758 return;
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) {
1767 kbtrans_vt_compose(upper, keyid, B_TRUE, buf);
1768 return;
1773 * These are the multi byte keys (Home, Up, Down ...)
1775 cp = &lower->kbtrans_keystringtab[entry & 0x0F][0];
1778 * Copy the string from the keystringtable, and send it
1779 * upstream a character at a time.
1781 while (*cp != '\0') {
1783 kbtrans_putcode(upper, (uchar_t)*cp);
1785 cp++;
1788 return;
1790 case PADKEYS:
1792 * These are the keys on the keypad. Look up the
1793 * answer in the kb_numlock_table and send it upstream.
1795 kbtrans_putcode(upper,
1796 lower->kbtrans_numlock_table[entry&0x1F]);
1798 return;
1800 case 0: /* normal character */
1801 default:
1802 break;
1806 * Send the char upstream.
1808 kbtrans_putcode(upper, entry);
1812 #define KB_SCANCODE_ALT 0xe2
1813 #define KB_SCANCODE_ALTGRAPH 0xe6
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.
1823 /* ARGSUSED */
1824 static void
1825 kbtrans_ascii_keyreleased(struct kbtrans *upper, kbtrans_key_t key)
1827 if (key == KB_SCANCODE_ALT || key == KB_SCANCODE_ALTGRAPH) {
1828 upper->vt_switch_keystate = VT_SWITCH_KEY_NONE;
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.
1837 /* ARGSUSED */
1838 static void
1839 kbtrans_ascii_setup_repeat(
1840 struct kbtrans *upper,
1841 uint_t entrytype,
1842 kbtrans_key_t key)
1844 struct kbtrans_lower *lower = &upper->kbtrans_lower;
1847 * Cancel any currently repeating keys. This will be a new
1848 * key to repeat.
1850 kbtrans_cancelrpt(upper);
1853 * Set the value of the key to be repeated.
1855 lower->kbtrans_repeatkey = key;
1858 * Start the timeout for repeating this key. kbtrans_rpt will
1859 * be called to repeat the key.
1861 upper->kbtrans_streams_rptid = qtimeout(upper->kbtrans_streams_readq,
1862 kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
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.
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)
1878 Firm_event fe;
1879 register char *cp;
1880 struct kbtrans_lower *lower = &upper->kbtrans_lower;
1883 * Based on the type of key, we may need to do some EVENT
1884 * specific post processing.
1886 switch (entrytype) {
1888 case SHIFTKEYS:
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.
1895 fe.id = SHIFT_CAPSLOCK + (entry & 0x0F);
1896 fe.value = 1;
1897 kbtrans_keypressed(upper, key, &fe, fe.id);
1899 return;
1901 case BUCKYBITS:
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.
1908 fe.id = SHIFT_META + (entry & 0x0F);
1909 fe.value = 1;
1910 kbtrans_keypressed(upper, key, &fe, fe.id);
1912 return;
1914 case FUNCKEYS:
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.
1923 fe.id = KEY_LEFTFIRST + (entry & 0x003F);
1924 fe.value = 1;
1927 * Assume "up" table only generates
1928 * shift changes.
1930 kbtrans_keypressed(upper, key, &fe, fe.id);
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.
1941 return;
1943 case STRING:
1945 * These are the multi byte keys (Home, Up, Down ...)
1947 cp = &lower->kbtrans_keystringtab[entry & 0x0F][0];
1950 * Copy the string from the keystringtable, and send it
1951 * upstream a character at a time.
1953 while (*cp != '\0') {
1955 kbtrans_send_esc_event(*cp, upper);
1957 cp++;
1960 return;
1962 case PADKEYS:
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.
1971 fe.id = VKEY_FIRSTPAD + (entry & 0x001F);
1972 fe.value = 1;
1975 * Assume "up" table only generates
1976 * shift changes.
1978 kbtrans_keypressed(upper, key, &fe, fe.id);
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.
1989 return;
1991 case FUNNY:
1993 * These are not events.
1995 switch (entry) {
1996 case IDLE:
1997 case RESET:
1998 case ERROR:
2000 * Something has happened. Mark all keys as released.
2002 kbtrans_streams_releaseall(upper);
2003 break;
2006 return;
2008 case 0: /* normal character */
2009 default:
2010 break;
2014 * Send the event upstream.
2016 fe.id = entry;
2018 fe.value = 1;
2020 kbtrans_queueevent(upper, &fe);
2024 * kbtrans_trans_event_keyreleased:
2025 * This is the function if we are in TR_EVENT mode and a key
2026 * is released.
2028 /* ARGSUSED */
2029 static void
2030 kbtrans_trans_event_keyreleased(struct kbtrans *upper, kbtrans_key_t key)
2033 * Mark the key as released and send an event upstream.
2035 kbtrans_keyreleased(upper, key);
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.
2044 static void
2045 kbtrans_trans_event_setup_repeat(
2046 struct kbtrans *upper,
2047 uint_t entrytype,
2048 kbtrans_key_t key)
2050 struct kbtrans_lower *lower = &upper->kbtrans_lower;
2053 * Function keys and keypad keys do not repeat when we are in
2054 * EVENT mode.
2056 if (entrytype == FUNCKEYS || entrytype == PADKEYS) {
2058 return;
2062 * Cancel any currently repeating keys. This will be a new
2063 * key to repeat.
2065 kbtrans_cancelrpt(upper);
2068 * Set the value of the key to be repeated.
2070 lower->kbtrans_repeatkey = key;
2073 * Start the timeout for repeating this key. kbtrans_rpt will
2074 * be called to repeat the key.
2076 upper->kbtrans_streams_rptid = qtimeout(upper->kbtrans_streams_readq,
2077 kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
2081 * Administer the key tables.
2085 * Old special codes.
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
2104 * Map old special codes to new ones.
2105 * Indexed by ((old special code) >> 4) & 0x07; add (old special code) & 0x0F.
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,
2120 * kbtrans_setkey:
2121 * Set individual keystation translation from old-style entry.
2123 static int
2124 kbtrans_setkey(struct kbtrans_lower *lower, struct kiockey *key, cred_t *cr)
2126 int strtabindex, i;
2127 keymap_entry_t *ke;
2128 register int tablemask;
2129 register keymap_entry_t entry;
2130 register struct keyboard *kp;
2132 kp = lower->kbtrans_keyboard;
2134 if (key->kio_station >= kp->k_keymap_size)
2135 return (EINVAL);
2137 if (lower->kbtrans_keyboard == NULL)
2139 return (EINVAL);
2141 tablemask = key->kio_tablemask;
2143 switch (tablemask) {
2144 case KIOCABORT1:
2145 case KIOCABORT1A:
2146 case KIOCABORT2:
2147 i = secpolicy_console(cr);
2148 if (i != 0)
2149 return (i);
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;
2162 return (0);
2165 if (tablemask & ALTGRAPHMASK)
2166 return (EINVAL);
2168 ke = kbtrans_find_entry(lower, (uint_t)tablemask, key->kio_station);
2169 if (ke == NULL)
2170 return (EINVAL);
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';
2180 entry = key->kio_entry;
2183 * There's nothing we need do with OLD_ISOCHAR.
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);
2196 *ke = entry;
2198 return (0);
2203 * Map new special codes to old ones.
2204 * Indexed by (new special code) >> 8; add (new special code) & 0xFF.
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 */
2218 * kbtrans_getkey:
2219 * Get individual keystation translation as old-style entry.
2221 static int
2222 kbtrans_getkey(struct kbtrans_lower *lower, struct kiockey *key)
2224 int strtabindex;
2225 keymap_entry_t *ke;
2226 register keymap_entry_t entry;
2227 struct keyboard *kp;
2229 kp = lower->kbtrans_keyboard;
2231 if (key->kio_station >= kp->k_keymap_size)
2232 return (EINVAL);
2234 if (lower->kbtrans_keyboard == NULL)
2235 return (EINVAL);
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);
2249 ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2250 key->kio_station);
2251 if (ke == NULL)
2252 return (EINVAL);
2254 entry = *ke;
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;
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);
2272 return (0);
2277 * kbtrans_skey:
2278 * Set individual keystation translation from new-style entry.
2280 static int
2281 kbtrans_skey(struct kbtrans_lower *lower, struct kiockeymap *key, cred_t *cr)
2283 int strtabindex, i;
2284 keymap_entry_t *ke;
2285 struct keyboard *kp;
2287 kp = lower->kbtrans_keyboard;
2289 if (key->kio_station >= kp->k_keymap_size) {
2290 return (EINVAL);
2294 if (lower->kbtrans_keyboard == NULL) {
2295 return (EINVAL);
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;
2316 return (0);
2319 ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2320 key->kio_station);
2321 if (ke == NULL)
2322 return (EINVAL);
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';
2332 *ke = key->kio_entry;
2334 return (0);
2339 * kbtrans_gkey:
2340 * Get individual keystation translation as new-style entry.
2342 static int
2343 kbtrans_gkey(struct kbtrans_lower *lower, struct kiockeymap *key)
2345 int strtabindex;
2346 keymap_entry_t *ke;
2347 struct keyboard *kp;
2349 kp = lower->kbtrans_keyboard;
2351 if (key->kio_station >= kp->k_keymap_size)
2352 return (EINVAL);
2354 if (lower->kbtrans_keyboard == NULL)
2355 return (EINVAL);
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);
2369 ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2370 key->kio_station);
2371 if (ke == NULL)
2372 return (EINVAL);
2374 key->kio_entry = *ke;
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);
2382 return (0);