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