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