xref: /titanic_51/usr/src/uts/common/io/kbtrans/kbtrans_streams.c (revision fe54a78e1aacf39261ad56e9903bce02e3fb6d21)
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 2008 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 "kbtrans_lower.h"
50 #include "kbtrans_streams.h"
51 
52 #ifdef DEBUG
53 int	kbtrans_errmask;
54 int	kbtrans_errlevel;
55 #endif
56 
57 #define	KB_NR_FUNCKEYS		12
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)"
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 			/* Shift key needs to be sent to upper immediately */
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 			}
473 			break;
474 		case ABORT_ABORT1_RECEIVED:
475 			upper->kbtrans_streams_abort_state = ABORT_NORMAL;
476 			if (state == KEY_PRESSED &&
477 			    key == (kbtrans_key_t)kp->k_abort2) {
478 				abort_sequence_enter((char *)NULL);
479 				return;
480 			} else {
481 				kbtrans_processkey(lower,
482 				    upper->kbtrans_streams_callback,
483 				    upper->kbtrans_streams_abort1_key,
484 				    KEY_PRESSED);
485 			}
486 			break;
487 		case NEW_ABORT_ABORT1_RECEIVED:
488 			upper->kbtrans_streams_abort_state = ABORT_NORMAL;
489 			if (state == KEY_PRESSED &&
490 			    key == (kbtrans_key_t)kp->k_newabort2) {
491 				abort_sequence_enter((char *)NULL);
492 				kbtrans_processkey(lower,
493 				    upper->kbtrans_streams_callback,
494 				    upper->kbtrans_streams_new_abort1_key,
495 				    KEY_RELEASED);
496 				return;
497 			}
498 		}
499 	}
500 
501 	kbtrans_processkey(lower, upper->kbtrans_streams_callback, key, state);
502 }
503 
504 /*
505  * kbtrans_streams_set_keyboard:
506  * 	At any time after calling kbtrans_streams_init, the hardware
507  * 	module should make this call to report the id of the keyboard
508  * 	attached. id is the keyboard type, typically KB_SUN4,
509  * 	KB_PC, or KB_USB.
510  */
511 void
512 kbtrans_streams_set_keyboard(
513     struct kbtrans 	*upper,
514     int 		id,
515     struct keyboard 	*k)
516 {
517 	upper->kbtrans_lower.kbtrans_keyboard = k;
518 	upper->kbtrans_streams_id = id;
519 }
520 
521 /*
522  * kbtrans_streams_has_reset:
523  * 	At any time between kbtrans_streams_init and kbtrans_streams_fini,
524  * 	the hardware module can call this routine to report that the
525  * 	keyboard has been reset, e.g. by being unplugged and reattached.
526  */
527 /*ARGSUSED*/
528 void
529 kbtrans_streams_has_reset(struct kbtrans *upper)
530 {
531 	/*
532 	 * If this routine is implemented it should probably (a)
533 	 * simulate releases of all pressed keys and (b) call
534 	 * the hardware module to set the LEDs.
535 	 */
536 }
537 
538 /*
539  * kbtrans_streams_enable:
540  *	This is the routine that is called back when the the stream is ready
541  *	to take messages.
542  */
543 void
544 kbtrans_streams_enable(struct kbtrans *upper)
545 {
546 	/* Set the LED's */
547 	kbtrans_setled(upper);
548 }
549 
550 /*
551  * kbtrans_streams_setled():
552  *	This is the routine that is called to only update the led state
553  *	in kbtrans.
554  */
555 void
556 kbtrans_streams_setled(struct kbtrans *upper, int led_state)
557 {
558 	struct kbtrans_lower *lower;
559 
560 	lower = &upper->kbtrans_lower;
561 	lower->kbtrans_led_state = (uchar_t)led_state;
562 
563 	if (lower->kbtrans_led_state & LED_CAPS_LOCK)
564 		lower->kbtrans_togglemask |= CAPSMASK;
565 	if (lower->kbtrans_led_state & LED_NUM_LOCK)
566 		lower->kbtrans_togglemask |= NUMLOCKMASK;
567 
568 #if	defined(SCROLLMASK)
569 	if (lower->kbtrans_led_state & LED_SCROLL_LOCK)
570 		lower->kbtrans_togglemask |= SCROLLMASK;
571 #endif
572 
573 	lower->kbtrans_shiftmask = lower->kbtrans_togglemask;
574 
575 }
576 
577 /*
578  * kbtrans_streams_set_queue:
579  *      Set the overlying queue, to support multiplexors.
580  */
581 void
582 kbtrans_streams_set_queue(struct kbtrans *upper, queue_t *q)
583 {
584 
585 	upper->kbtrans_streams_readq = q;
586 }
587 
588 /*
589  * kbtrans_streams_get_queue:
590  *      Return the overlying queue.
591  */
592 queue_t *
593 kbtrans_streams_get_queue(struct kbtrans *upper)
594 {
595 	return (upper->kbtrans_streams_readq);
596 }
597 
598 /*
599  * kbtrans_streams_untimeout
600  *      Cancell all timeout
601  */
602 void
603 kbtrans_streams_untimeout(struct kbtrans *upper)
604 {
605 	/* clear all timeouts */
606 	if (upper->kbtrans_streams_bufcallid) {
607 		qunbufcall(upper->kbtrans_streams_readq,
608 		    upper->kbtrans_streams_bufcallid);
609 		upper->kbtrans_streams_bufcallid = 0;
610 	}
611 	if (upper->kbtrans_streams_rptid) {
612 		(void) quntimeout(upper->kbtrans_streams_readq,
613 		    upper->kbtrans_streams_rptid);
614 		upper->kbtrans_streams_rptid = 0;
615 	}
616 }
617 
618 /*
619  * kbtrans_reioctl:
620  * 	This function is set up as call-back function should an ioctl fail
621  * 	to allocate required resources.
622  */
623 static void
624 kbtrans_reioctl(void	*arg)
625 {
626 	struct kbtrans *upper = (struct kbtrans *)arg;
627 	mblk_t *mp;
628 
629 	upper->kbtrans_streams_bufcallid = 0;
630 
631 	if ((mp = upper->kbtrans_streams_iocpending) != NULL) {
632 		/* not pending any more */
633 		upper->kbtrans_streams_iocpending = NULL;
634 		(void) kbtrans_ioctl(upper, mp);
635 	}
636 }
637 
638 /*
639  * kbtrans_ioctl:
640  * 	process ioctls we recognize and own.  Otherwise, pass it down.
641  */
642 static enum kbtrans_message_response
643 kbtrans_ioctl(struct kbtrans *upper, register mblk_t *mp)
644 {
645 	register struct iocblk *iocp;
646 	register short	new_translate;
647 	register Vuid_addr_probe *addr_probe;
648 	register short	*addr_ptr;
649 	size_t	ioctlrespsize;
650 	int	err = 0;
651 	struct kbtrans_lower *lower;
652 	mblk_t *datap;
653 	int	translate;
654 
655 	static int kiocgetkey, kiocsetkey;
656 
657 	lower = &upper->kbtrans_lower;
658 
659 	iocp = (struct iocblk *)mp->b_rptr;
660 
661 	DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper,
662 	    "kbtrans_ioctl: ioc_cmd 0x%x - ", iocp->ioc_cmd));
663 	switch (iocp->ioc_cmd) {
664 
665 	case VUIDSFORMAT:
666 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDSFORMAT\n"));
667 
668 		err = miocpullup(mp, sizeof (int));
669 		if (err != 0)
670 			break;
671 		new_translate = (*(int *)mp->b_cont->b_rptr == VUID_NATIVE) ?
672 		    TR_ASCII : TR_EVENT;
673 
674 		if (new_translate == upper->kbtrans_streams_translate_mode)
675 			break;
676 		upper->kbtrans_streams_translate_mode = new_translate;
677 
678 		kbtrans_set_translation_callback(upper);
679 
680 		kbtrans_flush(upper);
681 		break;
682 
683 	case KIOCTRANS:
684 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCTRANS\n"));
685 		err = miocpullup(mp, sizeof (int));
686 		if (err != 0)
687 			break;
688 		new_translate = *(int *)mp->b_cont->b_rptr;
689 		if (new_translate == upper->kbtrans_streams_translate_mode)
690 			break;
691 		upper->kbtrans_streams_translate_mode = new_translate;
692 		kbtrans_set_translation_callback(upper);
693 
694 		kbtrans_flush(upper);
695 		break;
696 
697 	case KIOCSLED:
698 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSLED\n"));
699 
700 		err = miocpullup(mp, sizeof (uchar_t));
701 		if (err != 0)
702 			break;
703 		lower->kbtrans_led_state = *(uchar_t *)mp->b_cont->b_rptr;
704 
705 		kbtrans_setled(upper);
706 		break;
707 
708 	case KIOCGLED:
709 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGLED\n"));
710 		if ((datap = allocb(sizeof (uchar_t), BPRI_HI)) == NULL) {
711 			ioctlrespsize = sizeof (int);
712 			goto allocfailure;
713 		}
714 
715 		*(uchar_t *)datap->b_wptr = lower->kbtrans_led_state;
716 		datap->b_wptr += sizeof (uchar_t);
717 		if (mp->b_cont)
718 			freemsg(mp->b_cont);
719 		mp->b_cont = datap;
720 		iocp->ioc_count = sizeof (uchar_t);
721 		break;
722 
723 	case VUIDGFORMAT:
724 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDGFORMAT\n"));
725 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
726 			ioctlrespsize = sizeof (int);
727 			goto allocfailure;
728 		}
729 		*(int *)datap->b_wptr =
730 		    (upper->kbtrans_streams_translate_mode == TR_EVENT ||
731 		    upper->kbtrans_streams_translate_mode == TR_UNTRANS_EVENT) ?
732 		    VUID_FIRM_EVENT: VUID_NATIVE;
733 		datap->b_wptr += sizeof (int);
734 		if (mp->b_cont)  /* free msg to prevent memory leak */
735 			freemsg(mp->b_cont);
736 		mp->b_cont = datap;
737 		iocp->ioc_count = sizeof (int);
738 		break;
739 
740 	case KIOCGTRANS:
741 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGTRANS\n"));
742 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
743 			ioctlrespsize = sizeof (int);
744 			goto allocfailure;
745 		}
746 		*(int *)datap->b_wptr = upper->kbtrans_streams_translate_mode;
747 		datap->b_wptr += sizeof (int);
748 		if (mp->b_cont)  /* free msg to prevent memory leak */
749 			freemsg(mp->b_cont);
750 		mp->b_cont = datap;
751 		iocp->ioc_count = sizeof (int);
752 		break;
753 
754 	case VUIDSADDR:
755 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDSADDR\n"));
756 
757 		err = miocpullup(mp, sizeof (Vuid_addr_probe));
758 		if (err != 0)
759 			break;
760 		addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
761 		switch (addr_probe->base) {
762 
763 		case ASCII_FIRST:
764 			addr_ptr = &upper->kbtrans_streams_vuid_addr.ascii;
765 			break;
766 
767 		case TOP_FIRST:
768 			addr_ptr = &upper->kbtrans_streams_vuid_addr.top;
769 			break;
770 
771 		case VKEY_FIRST:
772 			addr_ptr = &upper->kbtrans_streams_vuid_addr.vkey;
773 			break;
774 
775 		default:
776 			err = ENODEV;
777 		}
778 
779 		if ((err == 0) && (*addr_ptr != addr_probe->data.next)) {
780 			*addr_ptr = addr_probe->data.next;
781 			kbtrans_flush(upper);
782 		}
783 		break;
784 
785 	case VUIDGADDR:
786 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDGADDR\n"));
787 
788 		err = miocpullup(mp, sizeof (Vuid_addr_probe));
789 		if (err != 0)
790 			break;
791 		addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
792 		switch (addr_probe->base) {
793 
794 		case ASCII_FIRST:
795 			addr_probe->data.current =
796 			    upper->kbtrans_streams_vuid_addr.ascii;
797 			break;
798 
799 		case TOP_FIRST:
800 			addr_probe->data.current =
801 			    upper->kbtrans_streams_vuid_addr.top;
802 			break;
803 
804 		case VKEY_FIRST:
805 			addr_probe->data.current =
806 			    upper->kbtrans_streams_vuid_addr.vkey;
807 			break;
808 
809 		default:
810 			err = ENODEV;
811 		}
812 		break;
813 
814 	case KIOCTRANSABLE:
815 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCTRANSABLE\n"));
816 
817 		err = miocpullup(mp, sizeof (int));
818 		if (err != 0)
819 			break;
820 		/*
821 		 * called during console setup in kbconfig()
822 		 * If set to false, means we are a serial keyboard,
823 		 * and we should pass all data up without modification.
824 		 */
825 		translate = *(int *)mp->b_cont->b_rptr;
826 		if (upper->kbtrans_streams_translatable != translate)
827 			upper->kbtrans_streams_translatable = translate;
828 
829 		if (translate != TR_CAN)
830 			DPRINTF(PRINT_L4, PRINT_MASK_ALL, (upper,
831 			    "Cannot translate keyboard using tables.\n"));
832 		break;
833 
834 	case KIOCGTRANSABLE:
835 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGTRANSABLE\n"));
836 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
837 			ioctlrespsize = sizeof (int);
838 			goto allocfailure;
839 		}
840 		*(int *)datap->b_wptr = upper->kbtrans_streams_translatable;
841 		datap->b_wptr += sizeof (int);
842 		if (mp->b_cont)  /* free msg to prevent memory leak */
843 			freemsg(mp->b_cont);
844 		mp->b_cont = datap;
845 		iocp->ioc_count = sizeof (int);
846 		break;
847 
848 	case KIOCSCOMPAT:
849 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSCOMPAT\n"));
850 
851 		err = miocpullup(mp, sizeof (int));
852 		if (err != 0)
853 			break;
854 		lower->kbtrans_compat = *(int *)mp->b_cont->b_rptr;
855 		break;
856 
857 	case KIOCGCOMPAT:
858 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGCOMPAT\n"));
859 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
860 			ioctlrespsize = sizeof (int);
861 			goto allocfailure;
862 		}
863 		*(int *)datap->b_wptr = lower->kbtrans_compat;
864 		datap->b_wptr += sizeof (int);
865 		if (mp->b_cont)  /* free msg to prevent memory leak */
866 			freemsg(mp->b_cont);
867 		mp->b_cont = datap;
868 		iocp->ioc_count = sizeof (int);
869 		break;
870 
871 	case KIOCSETKEY:
872 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSETKEY %d\n",
873 		    kiocsetkey++));
874 		err = miocpullup(mp, sizeof (struct kiockey));
875 		if (err != 0)
876 			break;
877 		err = kbtrans_setkey(&upper->kbtrans_lower,
878 		    (struct kiockey *)mp->b_cont->b_rptr, iocp->ioc_cr);
879 		/*
880 		 * Since this only affects any subsequent key presses,
881 		 * don't flush soft state.  One might want to
882 		 * toggle the keytable entries dynamically.
883 		 */
884 		break;
885 
886 	case KIOCGETKEY:
887 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGETKEY %d\n",
888 		    kiocgetkey++));
889 		err = miocpullup(mp, sizeof (struct kiockey));
890 		if (err != 0)
891 			break;
892 		err = kbtrans_getkey(&upper->kbtrans_lower,
893 		    (struct kiockey *)mp->b_cont->b_rptr);
894 		break;
895 
896 	case KIOCSKEY:
897 		err = miocpullup(mp, sizeof (struct kiockeymap));
898 		if (err != 0)
899 			break;
900 		err = kbtrans_skey(&upper->kbtrans_lower,
901 		    (struct kiockeymap *)mp->b_cont->b_rptr, iocp->ioc_cr);
902 		/*
903 		 * Since this only affects any subsequent key presses,
904 		 * don't flush soft state.  One might want to
905 		 * toggle the keytable entries dynamically.
906 		 */
907 		break;
908 
909 	case KIOCGKEY:
910 		err = miocpullup(mp, sizeof (struct kiockeymap));
911 		if (err != 0)
912 			break;
913 		err = kbtrans_gkey(&upper->kbtrans_lower,
914 		    (struct kiockeymap *)mp->b_cont->b_rptr);
915 		break;
916 
917 	case KIOCSDIRECT:
918 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSDIRECT\n"));
919 		kbtrans_flush(upper);
920 		break;
921 
922 	case KIOCGDIRECT:
923 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSGDIRECT\n"));
924 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
925 			ioctlrespsize = sizeof (int);
926 			goto allocfailure;
927 		}
928 		*(int *)datap->b_wptr = 1;	/* always direct */
929 		datap->b_wptr += sizeof (int);
930 		if (mp->b_cont) /* free msg to prevent memory leak */
931 			freemsg(mp->b_cont);
932 		mp->b_cont = datap;
933 		iocp->ioc_count = sizeof (int);
934 		break;
935 
936 	case KIOCTYPE:
937 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCTYPE\n"));
938 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
939 			ioctlrespsize = sizeof (int);
940 			goto allocfailure;
941 		}
942 		*(int *)datap->b_wptr = upper->kbtrans_streams_id;
943 		datap->b_wptr += sizeof (int);
944 		if (mp->b_cont) /* free msg to prevent memory leak */
945 			freemsg(mp->b_cont);
946 		mp->b_cont = datap;
947 		iocp->ioc_count = sizeof (int);
948 		break;
949 
950 	case CONSSETABORTENABLE:
951 		/*
952 		 * Peek as it goes by; must be a TRANSPARENT ioctl.
953 		 */
954 		if (iocp->ioc_count != TRANSPARENT) {
955 			err = EINVAL;
956 			break;
957 		}
958 
959 		upper->kbtrans_streams_abortable =
960 		    (boolean_t)*(intptr_t *)mp->b_cont->b_rptr;
961 
962 		/*
963 		 * Let the hardware module see it too.
964 		 */
965 		return (KBTRANS_MESSAGE_NOT_HANDLED);
966 
967 	case KIOCGRPTDELAY:
968 		/*
969 		 * Report the autorepeat delay, unit in millisecond
970 		 */
971 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGRPTDELAY\n"));
972 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
973 			ioctlrespsize = sizeof (int);
974 			goto allocfailure;
975 		}
976 		*(int *)datap->b_wptr = TICK_TO_MSEC(kbtrans_repeat_delay);
977 		datap->b_wptr += sizeof (int);
978 
979 		/* free msg to prevent memory leak */
980 		if (mp->b_cont != NULL)
981 			freemsg(mp->b_cont);
982 		mp->b_cont = datap;
983 		iocp->ioc_count = sizeof (int);
984 		break;
985 
986 	case KIOCSRPTDELAY:
987 		/*
988 		 * Set the autorepeat delay
989 		 */
990 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSRPTDELAY\n"));
991 		err = miocpullup(mp, sizeof (int));
992 
993 		if (err != 0)
994 			break;
995 
996 		/* validate the input */
997 		if (*(int *)mp->b_cont->b_rptr < KIOCRPTDELAY_MIN) {
998 			err = EINVAL;
999 			break;
1000 		}
1001 		kbtrans_repeat_delay = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
1002 		if (kbtrans_repeat_delay <= 0)
1003 			kbtrans_repeat_delay = 1;
1004 		break;
1005 
1006 	case KIOCGRPTRATE:
1007 		/*
1008 		 * Report the autorepeat rate
1009 		 */
1010 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGRPTRATE\n"));
1011 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1012 			ioctlrespsize = sizeof (int);
1013 			goto allocfailure;
1014 		}
1015 		*(int *)datap->b_wptr = TICK_TO_MSEC(kbtrans_repeat_rate);
1016 		datap->b_wptr += sizeof (int);
1017 
1018 		/* free msg to prevent memory leak */
1019 		if (mp->b_cont != NULL)
1020 			freemsg(mp->b_cont);
1021 		mp->b_cont = datap;
1022 		iocp->ioc_count = sizeof (int);
1023 		break;
1024 
1025 	case KIOCSRPTRATE:
1026 		/*
1027 		 * Set the autorepeat rate
1028 		 */
1029 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSRPTRATE\n"));
1030 		err = miocpullup(mp, sizeof (int));
1031 
1032 		if (err != 0)
1033 			break;
1034 
1035 		/* validate the input */
1036 		if (*(int *)mp->b_cont->b_rptr < KIOCRPTRATE_MIN) {
1037 			err = EINVAL;
1038 			break;
1039 		}
1040 		kbtrans_repeat_rate = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
1041 		if (kbtrans_repeat_rate <= 0)
1042 			kbtrans_repeat_rate = 1;
1043 		break;
1044 
1045 	default:
1046 		DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "unknown\n"));
1047 		return (KBTRANS_MESSAGE_NOT_HANDLED);
1048 	} /* end switch */
1049 
1050 	if (err != 0) {
1051 		iocp->ioc_rval = 0;
1052 		iocp->ioc_error = err;
1053 		mp->b_datap->db_type = M_IOCNAK;
1054 	} else {
1055 		iocp->ioc_rval = 0;
1056 		iocp->ioc_error = 0;	/* brain rot */
1057 		mp->b_datap->db_type = M_IOCACK;
1058 	}
1059 	putnext(upper->kbtrans_streams_readq, mp);
1060 
1061 	return (KBTRANS_MESSAGE_HANDLED);
1062 
1063 allocfailure:
1064 	/*
1065 	 * We needed to allocate something to handle this "ioctl", but
1066 	 * couldn't; save this "ioctl" and arrange to get called back when
1067 	 * it's more likely that we can get what we need.
1068 	 * If there's already one being saved, throw it out, since it
1069 	 * must have timed out.
1070 	 */
1071 	if (upper->kbtrans_streams_iocpending != NULL)
1072 		freemsg(upper->kbtrans_streams_iocpending);
1073 	upper->kbtrans_streams_iocpending = mp;
1074 	if (upper->kbtrans_streams_bufcallid) {
1075 		qunbufcall(upper->kbtrans_streams_readq,
1076 		    upper->kbtrans_streams_bufcallid);
1077 	}
1078 	upper->kbtrans_streams_bufcallid =
1079 	    qbufcall(upper->kbtrans_streams_readq, ioctlrespsize, BPRI_HI,
1080 	    kbtrans_reioctl, upper);
1081 	/*
1082 	 * This is a white lie... we *will* handle it, eventually.
1083 	 */
1084 	return (KBTRANS_MESSAGE_HANDLED);
1085 }
1086 
1087 /*
1088  * kbtrans_flush:
1089  *	Flush data upstream
1090  */
1091 static void
1092 kbtrans_flush(register struct kbtrans *upper)
1093 {
1094 	register queue_t *q;
1095 
1096 	/* Flush pending data already sent upstream */
1097 	if ((q = upper->kbtrans_streams_readq) != NULL && q->q_next != NULL)
1098 		(void) putnextctl1(q, M_FLUSH, FLUSHR);
1099 
1100 	/* Flush pending ups */
1101 	bzero(upper->kbtrans_streams_downs, upper->kbtrans_streams_downs_bytes);
1102 
1103 	kbtrans_cancelrpt(upper);
1104 }
1105 
1106 /*
1107  * kbtrans_setled:
1108  *	 Update the keyboard LEDs to match the current keyboard state.
1109  */
1110 static void
1111 kbtrans_setled(struct kbtrans *upper)
1112 {
1113 	upper->kbtrans_streams_hw_callbacks->kbtrans_streams_setled(
1114 	    upper->kbtrans_streams_hw,
1115 	    upper->kbtrans_lower.kbtrans_led_state);
1116 }
1117 
1118 /*
1119  * kbtrans_rpt:
1120  *	If a key is held down, this function is set up to be called
1121  * 	after kbtrans_repeat_rate time elapses.
1122  */
1123 static void
1124 kbtrans_rpt(void *arg)
1125 {
1126 	struct kbtrans	*upper = arg;
1127 	struct kbtrans_lower	*lower = &upper->kbtrans_lower;
1128 
1129 	DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL,
1130 	    "kbtrans_rpt: repeat key %X\n",
1131 	    lower->kbtrans_repeatkey));
1132 
1133 	upper->kbtrans_streams_rptid = 0;
1134 
1135 	/*
1136 	 * NB:  polled code zaps kbtrans_repeatkey without cancelling
1137 	 * timeout.
1138 	 */
1139 	if (lower->kbtrans_repeatkey != 0) {
1140 		kbtrans_keyreleased(upper, lower->kbtrans_repeatkey);
1141 
1142 		kbtrans_processkey(lower,
1143 		    upper->kbtrans_streams_callback,
1144 		    lower->kbtrans_repeatkey,
1145 		    KEY_PRESSED);
1146 
1147 		upper->kbtrans_streams_rptid =
1148 		    qtimeout(upper->kbtrans_streams_readq, kbtrans_rpt,
1149 		    (caddr_t)upper, kbtrans_repeat_rate);
1150 	}
1151 }
1152 
1153 /*
1154  * kbtrans_cancelrpt:
1155  * 	Cancel the repeating key
1156  */
1157 static void
1158 kbtrans_cancelrpt(struct kbtrans	*upper)
1159 {
1160 	upper->kbtrans_lower.kbtrans_repeatkey = 0;
1161 
1162 	if (upper->kbtrans_streams_rptid != 0) {
1163 		(void) quntimeout(upper->kbtrans_streams_readq,
1164 		    upper->kbtrans_streams_rptid);
1165 		upper->kbtrans_streams_rptid = 0;
1166 	}
1167 }
1168 
1169 /*
1170  * kbtrans_send_esc_event:
1171  *	Send character up stream. Used for the case of
1172  *	sending strings upstream.
1173  */
1174 static void
1175 kbtrans_send_esc_event(char c, register struct kbtrans *upper)
1176 {
1177 	Firm_event fe;
1178 
1179 	fe.id = c;
1180 	fe.value = 1;
1181 	fe.pair_type = FE_PAIR_NONE;
1182 	fe.pair = 0;
1183 	/*
1184 	 * Pretend as if each cp pushed and released
1185 	 * Calling kbtrans_queueevent avoids addr translation
1186 	 * and pair base determination of kbtrans_keypressed.
1187 	 */
1188 	kbtrans_queueevent(upper, &fe);
1189 	fe.value = 0;
1190 	kbtrans_queueevent(upper, &fe);
1191 }
1192 
1193 /*
1194  * kbtrans_strsetwithdecimal:
1195  *	Used for expanding a function key to the ascii equivalent
1196  */
1197 static char *
1198 kbtrans_strsetwithdecimal(char *buf, uint_t val, uint_t maxdigs)
1199 {
1200 	int	hradix = 5;
1201 	char	*bp;
1202 	int	lowbit;
1203 	char	*tab = "0123456789abcdef";
1204 
1205 	bp = buf + maxdigs;
1206 	*(--bp) = '\0';
1207 	while (val) {
1208 		lowbit = val & 1;
1209 		val = (val >> 1);
1210 		*(--bp) = tab[val % hradix * 2 + lowbit];
1211 		val /= hradix;
1212 	}
1213 	return (bp);
1214 }
1215 
1216 /*
1217  * kbtrans_keypressed:
1218  *	Modify Firm event to be sent up the stream
1219  */
1220 static void
1221 kbtrans_keypressed(struct kbtrans *upper, uchar_t key_station,
1222 		    Firm_event *fe, ushort_t base)
1223 {
1224 
1225 	register short	id_addr;
1226 	struct kbtrans_lower	*lower = &upper->kbtrans_lower;
1227 
1228 	/* Set pair values */
1229 	if (fe->id < (ushort_t)VKEY_FIRST) {
1230 		/*
1231 		 * If CTRLed, find the ID that would have been used had it
1232 		 * not been CTRLed.
1233 		 */
1234 		if (lower->kbtrans_shiftmask & (CTRLMASK | CTLSMASK)) {
1235 			unsigned short *ke;
1236 			unsigned int mask;
1237 
1238 			mask = lower->kbtrans_shiftmask &
1239 			    ~(CTRLMASK | CTLSMASK | UPMASK);
1240 
1241 			ke = kbtrans_find_entry(lower, mask, key_station);
1242 			if (ke == NULL)
1243 				return;
1244 
1245 			base = *ke;
1246 		}
1247 		if (base != fe->id) {
1248 			fe->pair_type = FE_PAIR_SET;
1249 			fe->pair = (uchar_t)base;
1250 
1251 			goto send;
1252 		}
1253 	}
1254 	fe->pair_type = FE_PAIR_NONE;
1255 	fe->pair = 0;
1256 
1257 send:
1258 	/* Adjust event id address for multiple keyboard/workstation support */
1259 	switch (vuid_id_addr(fe->id)) {
1260 	case ASCII_FIRST:
1261 		id_addr = upper->kbtrans_streams_vuid_addr.ascii;
1262 		break;
1263 	case TOP_FIRST:
1264 		id_addr = upper->kbtrans_streams_vuid_addr.top;
1265 		break;
1266 	case VKEY_FIRST:
1267 		id_addr = upper->kbtrans_streams_vuid_addr.vkey;
1268 		break;
1269 	default:
1270 		id_addr = vuid_id_addr(fe->id);
1271 		break;
1272 	}
1273 	fe->id = vuid_id_offset(fe->id) | id_addr;
1274 
1275 	kbtrans_queuepress(upper, key_station, fe);
1276 }
1277 
1278 /*
1279  * kbtrans_queuepress:
1280  *	Add keypress to the "downs" table
1281  */
1282 static void
1283 kbtrans_queuepress(struct kbtrans *upper,
1284 		    uchar_t key_station, Firm_event *fe)
1285 {
1286 	register struct key_event *ke, *ke_free;
1287 	register int i;
1288 
1289 	DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL, "kbtrans_queuepress:"
1290 	    " key=%d", key_station));
1291 
1292 	ke_free = 0;
1293 
1294 	/* Scan table of down key stations */
1295 
1296 	for (i = 0, ke = upper->kbtrans_streams_downs;
1297 	    i < upper->kbtrans_streams_num_downs_entries; i++, ke++) {
1298 
1299 		/* Keycode already down? */
1300 		if (ke->key_station == key_station) {
1301 
1302 			DPRINTF(PRINT_L0, PRINT_MASK_ALL,
1303 			    (NULL, "kbtrans: Double "
1304 			    "entry in downs table (%d,%d)!\n",
1305 			    key_station, i));
1306 
1307 			goto add_event;
1308 		}
1309 
1310 		if (ke->key_station == 0)
1311 			ke_free = ke;
1312 	}
1313 
1314 	if (ke_free) {
1315 		ke = ke_free;
1316 		goto add_event;
1317 	}
1318 
1319 	ke = upper->kbtrans_streams_downs;
1320 
1321 add_event:
1322 	ke->key_station = key_station;
1323 	ke->event = *fe;
1324 	kbtrans_queueevent(upper, fe);
1325 }
1326 
1327 /*
1328  * kbtrans_keyreleased:
1329  * 	Remove entry from the downs table
1330  */
1331 static void
1332 kbtrans_keyreleased(register struct kbtrans *upper, uchar_t key_station)
1333 {
1334 	register struct key_event *ke;
1335 	register int i;
1336 
1337 	DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL, "RELEASE key=%d\n",
1338 	    key_station));
1339 
1340 	if (upper->kbtrans_streams_translate_mode != TR_EVENT &&
1341 	    upper->kbtrans_streams_translate_mode != TR_UNTRANS_EVENT) {
1342 
1343 		return;
1344 	}
1345 
1346 	/* Scan table of down key stations */
1347 	for (i = 0, ke = upper->kbtrans_streams_downs;
1348 	    i < upper->kbtrans_streams_num_downs_entries;
1349 	    i++, ke++) {
1350 		/* Found? */
1351 		if (ke->key_station == key_station) {
1352 			ke->key_station = 0;
1353 			ke->event.value = 0;
1354 			kbtrans_queueevent(upper, &ke->event);
1355 		}
1356 	}
1357 
1358 	/*
1359 	 * Ignore if couldn't find because may be called twice
1360 	 * for the same key station in the case of the kbtrans_rpt
1361 	 * routine being called unnecessarily.
1362 	 */
1363 }
1364 
1365 
1366 /*
1367  * kbtrans_putcode:
1368  *	 Pass a keycode up the stream, if you can, otherwise throw it away.
1369  */
1370 static void
1371 kbtrans_putcode(register struct kbtrans *upper, uint_t code)
1372 {
1373 	register mblk_t *bp;
1374 
1375 	/*
1376 	 * If we can't send it up, then we just drop it.
1377 	 */
1378 	if (!canputnext(upper->kbtrans_streams_readq)) {
1379 
1380 		return;
1381 	}
1382 
1383 	/*
1384 	 * Allocate a messsage block to send up.
1385 	 */
1386 	if ((bp = allocb(sizeof (uint_t), BPRI_HI)) == NULL) {
1387 
1388 		cmn_err(CE_WARN, "kbtrans_putcode: Can't allocate block\
1389 			for keycode.");
1390 
1391 		return;
1392 	}
1393 
1394 	/*
1395 	 * We will strip out any high order information here.
1396 	 */
1397 	/* NOTE the implicit cast here */
1398 	*bp->b_wptr++ = (uchar_t)code;
1399 
1400 	/*
1401 	 * Send the message up.
1402 	 */
1403 	(void) putnext(upper->kbtrans_streams_readq, bp);
1404 }
1405 
1406 
1407 /*
1408  * kbtrans_putbuf:
1409  *	Pass generated keycode sequence to upstream, if possible.
1410  */
1411 static void
1412 kbtrans_putbuf(char *buf, queue_t *q)
1413 {
1414 	register mblk_t *bp;
1415 
1416 	if (!canputnext(q)) {
1417 		cmn_err(CE_WARN, "kbtrans_putbuf: Can't put block for keycode");
1418 	} else {
1419 		if ((bp = allocb((int)strlen(buf), BPRI_HI)) == NULL) {
1420 			cmn_err(CE_WARN, "kbtrans_putbuf: "
1421 			    "Can't allocate block for keycode");
1422 		} else {
1423 			while (*buf) {
1424 				*bp->b_wptr++ = *buf;
1425 				buf++;
1426 			}
1427 			putnext(q, bp);
1428 		}
1429 	}
1430 }
1431 
1432 /*
1433  * kbtrans_queueevent:
1434  *	 Pass a VUID "firm event" up the stream, if you can.
1435  */
1436 static void
1437 kbtrans_queueevent(struct kbtrans *upper, Firm_event *fe)
1438 {
1439 	register queue_t *q;
1440 	register mblk_t *bp;
1441 
1442 	if ((q = upper->kbtrans_streams_readq) == NULL)
1443 
1444 		return;
1445 
1446 	if (!canputnext(q)) {
1447 		if (kbtrans_overflow_msg) {
1448 			DPRINTF(PRINT_L2, PRINT_MASK_ALL, (NULL,
1449 			    "kbtrans: Buffer flushed when overflowed."));
1450 		}
1451 
1452 		kbtrans_flush(upper);
1453 		upper->kbtrans_overflow_cnt++;
1454 	} else {
1455 		if ((bp = allocb(sizeof (Firm_event), BPRI_HI)) == NULL) {
1456 			cmn_err(CE_WARN, "kbtrans_queueevent: Can't allocate \
1457 					block for event.");
1458 		} else {
1459 			uniqtime32(&fe->time);
1460 			*(Firm_event *)bp->b_wptr = *fe;
1461 			bp->b_wptr += sizeof (Firm_event);
1462 			(void) putnext(q, bp);
1463 
1464 
1465 		}
1466 	}
1467 }
1468 
1469 /*
1470  * kbtrans_set_translation_callback:
1471  *	This code sets the translation_callback pointer based on the
1472  * 	translation mode.
1473  */
1474 static void
1475 kbtrans_set_translation_callback(register struct kbtrans *upper)
1476 {
1477 	switch (upper->kbtrans_streams_translate_mode) {
1478 
1479 	default:
1480 	case TR_ASCII:
1481 		upper->vt_switch_keystate = VT_SWITCH_KEY_NONE;
1482 
1483 		/* Discard any obsolete CTRL/ALT/SHIFT keys */
1484 		upper->kbtrans_lower.kbtrans_shiftmask &=
1485 		    ~(CTRLMASK | ALTMASK | SHIFTMASK);
1486 		upper->kbtrans_lower.kbtrans_togglemask &=
1487 		    ~(CTRLMASK | ALTMASK | SHIFTMASK);
1488 
1489 		upper->kbtrans_streams_callback = &ascii_callback;
1490 
1491 		break;
1492 
1493 	case TR_EVENT:
1494 		upper->kbtrans_streams_callback = &trans_event_callback;
1495 
1496 		break;
1497 
1498 	case TR_UNTRANS_EVENT:
1499 		upper->kbtrans_streams_callback = &untrans_event_callback;
1500 
1501 		break;
1502 	}
1503 }
1504 
1505 /*
1506  * kbtrans_untrans_keypressed_raw:
1507  *	This is the callback we get if we are in TR_UNTRANS_EVENT and a
1508  * 	key is pressed.  This code will just send the scancode up the
1509  * 	stream.
1510  */
1511 static void
1512 kbtrans_untrans_keypressed_raw(struct kbtrans *upper, kbtrans_key_t key)
1513 {
1514 	Firm_event	fe;
1515 
1516 	bzero(&fe, sizeof (fe));
1517 
1518 	/*
1519 	 * fill in the event
1520 	 */
1521 	fe.id = (unsigned short)key;
1522 	fe.value = 1;
1523 
1524 	/*
1525 	 * Send the event upstream.
1526 	 */
1527 	kbtrans_queuepress(upper, key, &fe);
1528 }
1529 
1530 /*
1531  * kbtrans_untrans_keyreleased_raw:
1532  *	This is the callback we get if we are in TR_UNTRANS_EVENT mode
1533  * 	and a key is released.  This code will just send the scancode up
1534  * 	the stream.
1535  */
1536 static void
1537 kbtrans_untrans_keyreleased_raw(struct kbtrans *upper, kbtrans_key_t key)
1538 {
1539 	/*
1540 	 * Deal with a key released event.
1541 	 */
1542 	kbtrans_keyreleased(upper, key);
1543 }
1544 
1545 /*
1546  * kbtrans_vt_compose:
1547  *   To compose the key sequences for virtual terminal switching.
1548  *
1549  *   'ALTL + F#'                for 1-12 terminals
1550  *   'ALTGR + F#'               for 13-24 terminals
1551  *   'ALT + UPARROW'            for last terminal
1552  *   'ALT + LEFTARROW'          for previous terminal
1553  *   'ALT + RIGHTARROW'         for next terminal
1554  *
1555  * the vt switching message is encoded as:
1556  *
1557  *   -------------------------------------------------------------
1558  *   |  \033  |  'Q'  |  vtno + 'A'  |  opcode  |  'z'  |  '\0'  |
1559  *   -------------------------------------------------------------
1560  *
1561  * opcode:
1562  *   'B'    to switch to previous terminal
1563  *   'F'    to switch to next terminal
1564  *   'L'    to switch to last terminal
1565  *   'H'    to switch to the terminal as specified by vtno,
1566  *          which is from 1 to 24.
1567  *
1568  * Here keyid is the keycode of UPARROW, LEFTARROW, or RIGHTARROW
1569  * when it is a kind of arrow key as indicated by is_arrow_key,
1570  * otherwise it indicates a function key and keyid is the number
1571  * corresponding to that function key.
1572  */
1573 static void
1574 kbtrans_vt_compose(struct kbtrans *upper, unsigned short keyid,
1575     boolean_t is_arrow_key, char *buf)
1576 {
1577 	char		*bufp;
1578 
1579 	bufp = buf;
1580 	*bufp++ = '\033'; /* Escape */
1581 	*bufp++ = 'Q';
1582 	if (is_arrow_key) {
1583 		*bufp++ = 'A';
1584 		switch (keyid) {
1585 		case UPARROW: /* last vt */
1586 			*bufp++ = 'L';
1587 			break;
1588 		case LEFTARROW: /* previous vt */
1589 			*bufp++ = 'B';
1590 			break;
1591 		case RIGHTARROW: /* next vt */
1592 			*bufp++ = 'F';
1593 			break;
1594 		default:
1595 			break;
1596 		}
1597 	} else {
1598 		/* this is funckey specifying vtno for switch */
1599 		*bufp++ = keyid +
1600 		    (upper->vt_switch_keystate - VT_SWITCH_KEY_ALT) *
1601 		    KB_NR_FUNCKEYS + 'A';
1602 		*bufp++ = 'H';
1603 	}
1604 	*bufp++ = 'z';
1605 	*bufp = '\0';
1606 
1607 	/*
1608 	 * Send the result upstream.
1609 	 */
1610 	kbtrans_putbuf(buf, upper->kbtrans_streams_readq);
1611 
1612 }
1613 
1614 /*
1615  * kbtrans_ascii_keypressed:
1616  *	This is the code if we are in TR_ASCII mode and a key
1617  * 	is pressed.  This is where we will do any special processing that
1618  * 	is specific to ASCII key translation.
1619  */
1620 /* ARGSUSED */
1621 static void
1622 kbtrans_ascii_keypressed(
1623     struct kbtrans	*upper,
1624     uint_t 		entrytype,
1625     kbtrans_key_t 	key,
1626     uint_t 		entry)
1627 {
1628 	register char	*cp;
1629 	register char	*bufp;
1630 	char		buf[14];
1631 	unsigned short		keyid;
1632 	struct kbtrans_lower	*lower = &upper->kbtrans_lower;
1633 
1634 	/*
1635 	 * Based on the type of key, we may need to do some ASCII
1636 	 * specific post processing. Note that the translated entry
1637 	 * is constructed as the actual keycode plus entrytype. see
1638 	 * sys/kbd.h for details of each entrytype.
1639 	 */
1640 	switch (entrytype) {
1641 
1642 	case BUCKYBITS:
1643 		return;
1644 
1645 	case SHIFTKEYS:
1646 		keyid = entry & 0xFF;
1647 		if (keyid == ALT) {
1648 			upper->vt_switch_keystate = VT_SWITCH_KEY_ALT;
1649 		} else if (keyid == ALTGRAPH) {
1650 			upper->vt_switch_keystate = VT_SWITCH_KEY_ALTGR;
1651 		}
1652 		return;
1653 
1654 	case FUNNY:
1655 		/*
1656 		 * There is no ascii equivalent.  We will ignore these
1657 		 * keys
1658 		 */
1659 		return;
1660 
1661 	case FUNCKEYS:
1662 		if (upper->vt_switch_keystate > VT_SWITCH_KEY_NONE) {
1663 			if (entry >= TOPFUNC &&
1664 			    entry < (TOPFUNC + KB_NR_FUNCKEYS)) {
1665 
1666 				/*
1667 				 * keyid is the number correspoding to F#
1668 				 * and its value is from 1 to 12.
1669 				 */
1670 				keyid = (entry & 0xF) + 1;
1671 
1672 				kbtrans_vt_compose(upper, keyid, B_FALSE, buf);
1673 				return;
1674 			}
1675 		}
1676 
1677 		/*
1678 		 * We need to expand this key to get the ascii
1679 		 * equivalent.  These are the function keys (F1, F2 ...)
1680 		 */
1681 		bufp = buf;
1682 		cp = kbtrans_strsetwithdecimal(bufp + 2,
1683 		    (uint_t)((entry & 0x003F) + 192),
1684 		    sizeof (buf) - 5);
1685 		*bufp++ = '\033'; /* Escape */
1686 		*bufp++ = '[';
1687 		while (*cp != '\0')
1688 			*bufp++ = *cp++;
1689 		*bufp++ = 'z';
1690 		*bufp = '\0';
1691 
1692 		/*
1693 		 * Send the result upstream.
1694 		 */
1695 		kbtrans_putbuf(buf, upper->kbtrans_streams_readq);
1696 
1697 		return;
1698 
1699 	case STRING:
1700 		if (upper->vt_switch_keystate > VT_SWITCH_KEY_NONE) {
1701 			keyid = entry & 0xFF;
1702 			if (keyid == UPARROW ||
1703 			    keyid == RIGHTARROW ||
1704 			    keyid == LEFTARROW) {
1705 
1706 				kbtrans_vt_compose(upper, keyid, B_TRUE, buf);
1707 				return;
1708 			}
1709 		}
1710 
1711 		/*
1712 		 * These are the multi byte keys (Home, Up, Down ...)
1713 		 */
1714 		cp = &lower->kbtrans_keystringtab[entry & 0x0F][0];
1715 
1716 		/*
1717 		 * Copy the string from the keystringtable, and send it
1718 		 * upstream a character at a time.
1719 		 */
1720 		while (*cp != '\0') {
1721 
1722 			kbtrans_putcode(upper, (uchar_t)*cp);
1723 
1724 			cp++;
1725 		}
1726 
1727 		return;
1728 
1729 	case PADKEYS:
1730 		/*
1731 		 * These are the keys on the keypad.  Look up the
1732 		 * answer in the kb_numlock_table and send it upstream.
1733 		 */
1734 		kbtrans_putcode(upper,
1735 		    lower->kbtrans_numlock_table[entry&0x1F]);
1736 
1737 		return;
1738 
1739 	case 0:	/* normal character */
1740 	default:
1741 		break;
1742 	}
1743 
1744 	/*
1745 	 * Send the byte upstream.
1746 	 */
1747 	kbtrans_putcode(upper, entry);
1748 
1749 }
1750 
1751 #define	KB_SCANCODE_ALT		0xe2
1752 #define	KB_SCANCODE_ALTGRAPH	0xe6
1753 
1754 /*
1755  * kbtrans_ascii_keyreleased:
1756  *	This is the function if we are in TR_ASCII mode and a key
1757  * 	is released.  ASCII doesn't have the concept of released keys,
1758  * 	or make/break codes.  So there is nothing for us to do except
1759  *      checking 'Alt/AltGraph' release key in order to reset the state
1760  *      of vt switch key sequence.
1761  */
1762 /* ARGSUSED */
1763 static void
1764 kbtrans_ascii_keyreleased(struct kbtrans *upper, kbtrans_key_t key)
1765 {
1766 	if (key == KB_SCANCODE_ALT || key == KB_SCANCODE_ALTGRAPH) {
1767 		upper->vt_switch_keystate = VT_SWITCH_KEY_NONE;
1768 	}
1769 }
1770 
1771 /*
1772  * kbtrans_ascii_setup_repeat:
1773  *	This is the function if we are in TR_ASCII mode and the
1774  * 	translation module has decided that a key needs to be repeated.
1775  */
1776 /* ARGSUSED */
1777 static void
1778 kbtrans_ascii_setup_repeat(
1779     struct kbtrans *upper,
1780     uint_t entrytype,
1781     kbtrans_key_t key)
1782 {
1783 	struct kbtrans_lower *lower = &upper->kbtrans_lower;
1784 
1785 	/*
1786 	 * Cancel any currently repeating keys.  This will be a new
1787 	 * key to repeat.
1788 	 */
1789 	kbtrans_cancelrpt(upper);
1790 
1791 	/*
1792 	 * Set the value of the key to be repeated.
1793 	 */
1794 	lower->kbtrans_repeatkey = key;
1795 
1796 	/*
1797 	 * Start the timeout for repeating this key.  kbtrans_rpt will
1798 	 * be called to repeat the key.
1799 	 */
1800 	upper->kbtrans_streams_rptid = qtimeout(upper->kbtrans_streams_readq,
1801 	    kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
1802 }
1803 
1804 /*
1805  * kbtrans_trans_event_keypressed:
1806  *	This is the function if we are in TR_EVENT mode and a key
1807  * 	is pressed.  This is where we will do any special processing that
1808  * 	is specific to EVENT key translation.
1809  */
1810 static void
1811 kbtrans_trans_event_keypressed(
1812 	struct kbtrans 	*upper,
1813 	uint_t 		entrytype,
1814 	kbtrans_key_t 	key,
1815 	uint_t 		entry)
1816 {
1817 	Firm_event	fe;
1818 	register char	*cp;
1819 	struct kbtrans_lower	*lower = &upper->kbtrans_lower;
1820 
1821 	/*
1822 	 * Based on the type of key, we may need to do some EVENT
1823 	 * specific post processing.
1824 	 */
1825 	switch (entrytype) {
1826 
1827 	case SHIFTKEYS:
1828 		/*
1829 		 * Relying on ordinal correspondence between
1830 		 * vuid_event.h SHIFT_META-SHIFT_TOP &
1831 		 * kbd.h METABIT-SYSTEMBIT in order to
1832 		 * correctly translate entry into fe.id.
1833 		 */
1834 		fe.id = SHIFT_CAPSLOCK + (entry & 0x0F);
1835 		fe.value = 1;
1836 		kbtrans_keypressed(upper, key, &fe, fe.id);
1837 
1838 		return;
1839 
1840 	case BUCKYBITS:
1841 		/*
1842 		 * Relying on ordinal correspondence between
1843 		 * vuid_event.h SHIFT_CAPSLOCK-SHIFT_RIGHTCTRL &
1844 		 * kbd.h CAPSLOCK-RIGHTCTRL in order to
1845 		 * correctly translate entry into fe.id.
1846 		 */
1847 		fe.id = SHIFT_META + (entry & 0x0F);
1848 		fe.value = 1;
1849 		kbtrans_keypressed(upper, key, &fe, fe.id);
1850 
1851 		return;
1852 
1853 	case FUNCKEYS:
1854 		/*
1855 		 * Take advantage of the similar
1856 		 * ordering of kbd.h function keys and
1857 		 * vuid_event.h function keys to do a
1858 		 * simple translation to achieve a
1859 		 * mapping between the 2 different
1860 		 * address spaces.
1861 		 */
1862 		fe.id = KEY_LEFTFIRST + (entry & 0x003F);
1863 		fe.value = 1;
1864 
1865 		/*
1866 		 * Assume "up" table only generates
1867 		 * shift changes.
1868 		 */
1869 		kbtrans_keypressed(upper, key, &fe, fe.id);
1870 
1871 		/*
1872 		 * Function key events can be expanded
1873 		 * by terminal emulator software to
1874 		 * produce the standard escape sequence
1875 		 * generated by the TR_ASCII case above
1876 		 * if a function key event is not used
1877 		 * by terminal emulator software
1878 		 * directly.
1879 		 */
1880 		return;
1881 
1882 	case STRING:
1883 		/*
1884 		 * These are the multi byte keys (Home, Up, Down ...)
1885 		 */
1886 		cp = &lower->kbtrans_keystringtab[entry & 0x0F][0];
1887 
1888 		/*
1889 		 * Copy the string from the keystringtable, and send it
1890 		 * upstream a character at a time.
1891 		 */
1892 		while (*cp != '\0') {
1893 
1894 			kbtrans_send_esc_event(*cp, upper);
1895 
1896 			cp++;
1897 		}
1898 
1899 		return;
1900 
1901 	case PADKEYS:
1902 		/*
1903 		 * Take advantage of the similar
1904 		 * ordering of kbd.h keypad keys and
1905 		 * vuid_event.h keypad keys to do a
1906 		 * simple translation to achieve a
1907 		 * mapping between the 2 different
1908 		 * address spaces.
1909 		 */
1910 		fe.id = VKEY_FIRSTPAD + (entry & 0x001F);
1911 		fe.value = 1;
1912 
1913 		/*
1914 		 * Assume "up" table only generates
1915 		 * shift changes.
1916 		 */
1917 		kbtrans_keypressed(upper, key, &fe, fe.id);
1918 
1919 		/*
1920 		 * Keypad key events can be expanded
1921 		 * by terminal emulator software to
1922 		 * produce the standard ascii character
1923 		 * generated by the TR_ASCII case above
1924 		 * if a keypad key event is not used
1925 		 * by terminal emulator software
1926 		 * directly.
1927 		 */
1928 		return;
1929 
1930 	case FUNNY:
1931 		/*
1932 		 * These are not events.
1933 		 */
1934 		switch (entry) {
1935 		case IDLE:
1936 		case RESET:
1937 		case ERROR:
1938 			/*
1939 			 * Something has happened.  Mark all keys as released.
1940 			 */
1941 			kbtrans_streams_releaseall(upper);
1942 			break;
1943 		}
1944 
1945 		return;
1946 
1947 	case 0: /* normal character */
1948 	default:
1949 		break;
1950 	}
1951 
1952 	/*
1953 	 * Send the event upstream.
1954 	 */
1955 	fe.id = entry;
1956 
1957 	fe.value = 1;
1958 
1959 	kbtrans_queueevent(upper, &fe);
1960 }
1961 
1962 /*
1963  * kbtrans_trans_event_keyreleased:
1964  *	This is the function if we are in TR_EVENT mode and a key
1965  * 	is released.
1966  */
1967 /* ARGSUSED */
1968 static void
1969 kbtrans_trans_event_keyreleased(struct kbtrans *upper, kbtrans_key_t key)
1970 {
1971 	/*
1972 	 * Mark the key as released and send an event upstream.
1973 	 */
1974 	kbtrans_keyreleased(upper, key);
1975 }
1976 
1977 /*
1978  * kbtrans_trans_event_setup_repeat:
1979  *	This is the function if we are in TR_EVENT mode and the
1980  *	translation module has decided that a key needs to be repeated.
1981  * 	We will set a timeout to retranslate the repeat key.
1982  */
1983 static void
1984 kbtrans_trans_event_setup_repeat(
1985 	struct kbtrans	*upper,
1986 	uint_t 		entrytype,
1987 	kbtrans_key_t	key)
1988 {
1989 	struct kbtrans_lower *lower = &upper->kbtrans_lower;
1990 
1991 	/*
1992 	 * Function keys and keypad keys do not repeat when we are in
1993 	 * EVENT mode.
1994 	 */
1995 	if (entrytype == FUNCKEYS || entrytype == PADKEYS) {
1996 
1997 		return;
1998 	}
1999 
2000 	/*
2001 	 * Cancel any currently repeating keys.  This will be a new
2002 	 * key to repeat.
2003 	 */
2004 	kbtrans_cancelrpt(upper);
2005 
2006 	/*
2007 	 * Set the value of the key to be repeated.
2008 	 */
2009 	lower->kbtrans_repeatkey = key;
2010 
2011 	/*
2012 	 * Start the timeout for repeating this key.  kbtrans_rpt will
2013 	 * be called to repeat the key.
2014 	 */
2015 	upper->kbtrans_streams_rptid = qtimeout(upper->kbtrans_streams_readq,
2016 	    kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
2017 }
2018 
2019 /*
2020  * Administer the key tables.
2021  */
2022 
2023 /*
2024  * Old special codes.
2025  */
2026 #define	OLD_SHIFTKEYS	0x80
2027 #define	OLD_BUCKYBITS	0x90
2028 #define	OLD_FUNNY	0xA0
2029 #define	OLD_FA_UMLAUT	0xA9
2030 #define	OLD_FA_CFLEX	0xAA
2031 #define	OLD_FA_TILDE	0xAB
2032 #define	OLD_FA_CEDILLA	0xAC
2033 #define	OLD_FA_ACUTE	0xAD
2034 #define	OLD_FA_GRAVE	0xAE
2035 #define	OLD_ISOCHAR	0xAF
2036 #define	OLD_STRING	0xB0
2037 #define	OLD_LEFTFUNC	0xC0
2038 #define	OLD_RIGHTFUNC	0xD0
2039 #define	OLD_TOPFUNC	0xE0
2040 #define	OLD_BOTTOMFUNC	0xF0
2041 
2042 /*
2043  * Map old special codes to new ones.
2044  * Indexed by ((old special code) >> 4) & 0x07; add (old special code) & 0x0F.
2045  */
2046 static ushort_t  special_old_to_new[] = {
2047 	SHIFTKEYS,
2048 	BUCKYBITS,
2049 	FUNNY,
2050 	STRING,
2051 	LEFTFUNC,
2052 	RIGHTFUNC,
2053 	TOPFUNC,
2054 	BOTTOMFUNC,
2055 };
2056 
2057 
2058 /*
2059  * kbtrans_setkey:
2060  *	 Set individual keystation translation from old-style entry.
2061  */
2062 static int
2063 kbtrans_setkey(struct kbtrans_lower *lower, struct kiockey *key, cred_t *cr)
2064 {
2065 	int	strtabindex, i;
2066 	unsigned short	*ke;
2067 	register int tablemask;
2068 	register ushort_t entry;
2069 	register struct keyboard *kp;
2070 
2071 	kp = lower->kbtrans_keyboard;
2072 
2073 	if (key->kio_station >= kp->k_keymap_size)
2074 
2075 		return (EINVAL);
2076 
2077 	if (lower->kbtrans_keyboard == NULL)
2078 
2079 		return (EINVAL);
2080 
2081 	tablemask = key->kio_tablemask;
2082 
2083 	switch (tablemask) {
2084 	case KIOCABORT1:
2085 	case KIOCABORT1A:
2086 	case KIOCABORT2:
2087 		i = secpolicy_console(cr);
2088 		if (i != 0)
2089 			return (i);
2090 
2091 		switch (tablemask) {
2092 		case KIOCABORT1:
2093 			kp->k_abort1 = key->kio_station;
2094 			break;
2095 		case KIOCABORT1A:
2096 			kp->k_abort1a = key->kio_station;
2097 			break;
2098 		case KIOCABORT2:
2099 			kp->k_abort2 = key->kio_station;
2100 			break;
2101 		}
2102 		return (0);
2103 	}
2104 
2105 	if (tablemask & ALTGRAPHMASK)
2106 		return (EINVAL);
2107 
2108 	ke = kbtrans_find_entry(lower, (uint_t)tablemask, key->kio_station);
2109 	if (ke == NULL)
2110 		return (EINVAL);
2111 
2112 	if (key->kio_entry >= (uchar_t)OLD_STRING &&
2113 	    key->kio_entry <= (uchar_t)(OLD_STRING + 15)) {
2114 		strtabindex = key->kio_entry - OLD_STRING;
2115 		bcopy(key->kio_string,
2116 		    lower->kbtrans_keystringtab[strtabindex], KTAB_STRLEN);
2117 		lower->kbtrans_keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
2118 	}
2119 
2120 	entry = key->kio_entry;
2121 
2122 	/*
2123 	 * There's nothing we need do with OLD_ISOCHAR.
2124 	 */
2125 	if (entry != OLD_ISOCHAR) {
2126 		if (entry & 0x80) {
2127 			if (entry >= OLD_FA_UMLAUT && entry <= OLD_FA_GRAVE)
2128 				entry = FA_CLASS + (entry & 0x0F) - 9;
2129 			else
2130 				entry =
2131 				    special_old_to_new[entry >> 4 & 0x07]
2132 				    + (entry & 0x0F);
2133 		}
2134 	}
2135 
2136 	*ke = entry;
2137 
2138 	return (0);
2139 }
2140 
2141 
2142 /*
2143  * Map new special codes to old ones.
2144  * Indexed by (new special code) >> 8; add (new special code) & 0xFF.
2145  */
2146 static uchar_t   special_new_to_old[] = {
2147 	0,			/* normal */
2148 	OLD_SHIFTKEYS,		/* SHIFTKEYS */
2149 	OLD_BUCKYBITS,		/* BUCKYBITS */
2150 	OLD_FUNNY,		/* FUNNY */
2151 	OLD_FA_UMLAUT,		/* FA_CLASS */
2152 	OLD_STRING,		/* STRING */
2153 	OLD_LEFTFUNC,		/* FUNCKEYS */
2154 };
2155 
2156 
2157 /*
2158  * kbtrans_getkey:
2159  *	Get individual keystation translation as old-style entry.
2160  */
2161 static int
2162 kbtrans_getkey(struct kbtrans_lower *lower, struct kiockey *key)
2163 {
2164 	int	strtabindex;
2165 	unsigned short	*ke;
2166 	register ushort_t entry;
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 	entry = *ke;
2195 
2196 	if (entry & 0xFF00)
2197 		key->kio_entry =
2198 		    special_new_to_old[(ushort_t)(entry & 0xFF00) >> 8]
2199 		    + (entry & 0x00FF);
2200 	else {
2201 		if (entry & 0x80)
2202 			key->kio_entry = (ushort_t)OLD_ISOCHAR;	/* you lose */
2203 		else
2204 			key->kio_entry = (ushort_t)entry;
2205 	}
2206 
2207 	if (entry >= STRING && entry <= (uchar_t)(STRING + 15)) {
2208 		strtabindex = entry - STRING;
2209 		bcopy(lower->kbtrans_keystringtab[strtabindex],
2210 		    key->kio_string, KTAB_STRLEN);
2211 	}
2212 	return (0);
2213 }
2214 
2215 
2216 /*
2217  * kbtrans_skey:
2218  *	Set individual keystation translation from new-style entry.
2219  */
2220 static int
2221 kbtrans_skey(struct kbtrans_lower *lower, struct kiockeymap *key, cred_t *cr)
2222 {
2223 	int	strtabindex, i;
2224 	unsigned short *ke;
2225 	struct keyboard *kp;
2226 
2227 	kp = lower->kbtrans_keyboard;
2228 
2229 	if (key->kio_station >= kp->k_keymap_size) {
2230 		return (EINVAL);
2231 
2232 	}
2233 
2234 	if (lower->kbtrans_keyboard == NULL) {
2235 		return (EINVAL);
2236 	}
2237 
2238 	switch (key->kio_tablemask) {
2239 	case KIOCABORT1:
2240 	case KIOCABORT1A:
2241 	case KIOCABORT2:
2242 		i = secpolicy_console(cr);
2243 		if (i != 0)
2244 			return (i);
2245 		switch (key->kio_tablemask) {
2246 		case KIOCABORT1:
2247 			kp->k_abort1 = key->kio_station;
2248 			break;
2249 		case KIOCABORT1A:
2250 			kp->k_abort1a = key->kio_station;
2251 			break;
2252 		case KIOCABORT2:
2253 			kp->k_abort2 = key->kio_station;
2254 			break;
2255 		}
2256 		return (0);
2257 	}
2258 
2259 	ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2260 	    key->kio_station);
2261 	if (ke == NULL)
2262 		return (EINVAL);
2263 
2264 	if (key->kio_entry >= STRING &&
2265 	    key->kio_entry <= (ushort_t)(STRING + 15)) {
2266 		strtabindex = key->kio_entry-STRING;
2267 		bcopy(key->kio_string,
2268 		    lower->kbtrans_keystringtab[strtabindex], KTAB_STRLEN);
2269 		lower->kbtrans_keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
2270 	}
2271 
2272 	*ke = key->kio_entry;
2273 
2274 	return (0);
2275 }
2276 
2277 
2278 /*
2279  * kbtrans_gkey:
2280  *	Get individual keystation translation as new-style entry.
2281  */
2282 static int
2283 kbtrans_gkey(struct kbtrans_lower *lower, struct	kiockeymap *key)
2284 {
2285 	int	strtabindex;
2286 	unsigned short *ke;
2287 	struct keyboard *kp;
2288 
2289 	kp = lower->kbtrans_keyboard;
2290 
2291 	if (key->kio_station >= kp->k_keymap_size)
2292 		return (EINVAL);
2293 
2294 	if (lower->kbtrans_keyboard == NULL)
2295 		return (EINVAL);
2296 
2297 	switch (key->kio_tablemask) {
2298 	case KIOCABORT1:
2299 		key->kio_station = kp->k_abort1;
2300 		return (0);
2301 	case KIOCABORT1A:
2302 		key->kio_station = kp->k_abort1a;
2303 		return (0);
2304 	case KIOCABORT2:
2305 		key->kio_station = kp->k_abort2;
2306 		return (0);
2307 	}
2308 
2309 	ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2310 	    key->kio_station);
2311 	if (ke == NULL)
2312 		return (EINVAL);
2313 
2314 	key->kio_entry = *ke;
2315 
2316 	if (key->kio_entry >= STRING &&
2317 	    key->kio_entry <= (ushort_t)(STRING + 15)) {
2318 		strtabindex = key->kio_entry-STRING;
2319 		bcopy(lower->kbtrans_keystringtab[strtabindex],
2320 		    key->kio_string, KTAB_STRLEN);
2321 	}
2322 	return (0);
2323 }
2324