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