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