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