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