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