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