xref: /titanic_54/usr/src/uts/common/io/kbd.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 						/* SunOS-4.0 1.60	*/
29*7c478bd9Sstevel@tonic-gate /*	From:	SunOS4.0	sundev/kbd.c	*/
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate /*
32*7c478bd9Sstevel@tonic-gate  * Keyboard input streams module - handles conversion of up/down codes to
33*7c478bd9Sstevel@tonic-gate  * ASCII or event format.
34*7c478bd9Sstevel@tonic-gate  */
35*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/signal.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/termios.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/termio.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/uio.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/consdev.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/kbd.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/kbio.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/kbdreg.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/vuid_event.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/policy.h>
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate static struct streamtab kbd_info;
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate static struct fmodsw fsw = {
64*7c478bd9Sstevel@tonic-gate 	"kb",
65*7c478bd9Sstevel@tonic-gate 	&kbd_info,
66*7c478bd9Sstevel@tonic-gate 	D_MP | D_MTPERMOD
67*7c478bd9Sstevel@tonic-gate };
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate /*
70*7c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
71*7c478bd9Sstevel@tonic-gate  */
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
74*7c478bd9Sstevel@tonic-gate 	&mod_strmodops, "streams module for keyboard", &fsw
75*7c478bd9Sstevel@tonic-gate };
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
78*7c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modlstrmod, NULL
79*7c478bd9Sstevel@tonic-gate };
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate int
82*7c478bd9Sstevel@tonic-gate _init(void)
83*7c478bd9Sstevel@tonic-gate {
84*7c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
85*7c478bd9Sstevel@tonic-gate }
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate int
88*7c478bd9Sstevel@tonic-gate _fini(void)
89*7c478bd9Sstevel@tonic-gate {
90*7c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
91*7c478bd9Sstevel@tonic-gate }
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate int
94*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
95*7c478bd9Sstevel@tonic-gate {
96*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
97*7c478bd9Sstevel@tonic-gate }
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate /*
100*7c478bd9Sstevel@tonic-gate  * For now these are shared.
101*7c478bd9Sstevel@tonic-gate  * These data structures are static (defined in keytables.c) thus
102*7c478bd9Sstevel@tonic-gate  * there is no need to perform any locking.
103*7c478bd9Sstevel@tonic-gate  */
104*7c478bd9Sstevel@tonic-gate extern struct keyboards	keytables[];
105*7c478bd9Sstevel@tonic-gate extern char keystringtab[16][KTAB_STRLEN];
106*7c478bd9Sstevel@tonic-gate extern struct compose_sequence_t kb_compose_table[];
107*7c478bd9Sstevel@tonic-gate extern signed char kb_compose_map[];
108*7c478bd9Sstevel@tonic-gate extern struct fltaccent_sequence_t kb_fltaccent_table[];
109*7c478bd9Sstevel@tonic-gate extern uchar_t kb_numlock_table[];
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate /*
112*7c478bd9Sstevel@tonic-gate  * This value corresponds approximately to max 10 fingers
113*7c478bd9Sstevel@tonic-gate  */
114*7c478bd9Sstevel@tonic-gate static int	kbd_downs_size = 15;
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate typedef	struct	key_event {
117*7c478bd9Sstevel@tonic-gate 	uchar_t	key_station;	/* Physical key station associated with event */
118*7c478bd9Sstevel@tonic-gate 	Firm_event event;	/* Event that sent out on down */
119*7c478bd9Sstevel@tonic-gate } Key_event;
120*7c478bd9Sstevel@tonic-gate struct	kbddata {
121*7c478bd9Sstevel@tonic-gate 	queue_t	*kbdd_readq;
122*7c478bd9Sstevel@tonic-gate 	queue_t *kbdd_writeq;
123*7c478bd9Sstevel@tonic-gate 	mblk_t	*kbdd_iocpending;	/* "ioctl" awaiting buffer */
124*7c478bd9Sstevel@tonic-gate 	mblk_t	*kbdd_replypending;	/* "ioctl" reply awaiting result */
125*7c478bd9Sstevel@tonic-gate 	int	kbdd_flags;		/* random flags */
126*7c478bd9Sstevel@tonic-gate 	bufcall_id_t kbdd_bufcallid;	/* bufcall id */
127*7c478bd9Sstevel@tonic-gate 	timeout_id_t kbdd_rptid;	/* timeout id for kbdrpt() */
128*7c478bd9Sstevel@tonic-gate 	timeout_id_t kbdd_layoutid;	/* timeout id for kbdlayout() */
129*7c478bd9Sstevel@tonic-gate 	int	kbdd_iocid;		/* ID of "ioctl" being waited for */
130*7c478bd9Sstevel@tonic-gate 	int	kbdd_iocerror;		/* error return from "ioctl" */
131*7c478bd9Sstevel@tonic-gate 	struct	keyboardstate kbdd_state;
132*7c478bd9Sstevel@tonic-gate 					/*
133*7c478bd9Sstevel@tonic-gate 					 * State of keyboard & keyboard
134*7c478bd9Sstevel@tonic-gate 					 * specific settings, e.g., tables
135*7c478bd9Sstevel@tonic-gate 					 */
136*7c478bd9Sstevel@tonic-gate 	int	kbdd_translate;		/* Translate keycodes? */
137*7c478bd9Sstevel@tonic-gate 	int	kbdd_translatable;	/* Keyboard is translatable? */
138*7c478bd9Sstevel@tonic-gate 	int	kbdd_compat;		/* Generating pre-4.1 events? */
139*7c478bd9Sstevel@tonic-gate 	short	kbdd_ascii_addr;	/* Vuid_id_addr for ascii events */
140*7c478bd9Sstevel@tonic-gate 	short	kbdd_top_addr;		/* Vuid_id_addr for top events */
141*7c478bd9Sstevel@tonic-gate 	short	kbdd_vkey_addr;		/* Vuid_id_addr for vkey events */
142*7c478bd9Sstevel@tonic-gate 	struct	key_event *kbdd_downs;
143*7c478bd9Sstevel@tonic-gate 					/*
144*7c478bd9Sstevel@tonic-gate 					 * Table of key stations currently down
145*7c478bd9Sstevel@tonic-gate 					 * that have firm events that need
146*7c478bd9Sstevel@tonic-gate 					 * to be matched with up transitions
147*7c478bd9Sstevel@tonic-gate 					 * when kbdd_translate is TR_*EVENT
148*7c478bd9Sstevel@tonic-gate 					 */
149*7c478bd9Sstevel@tonic-gate 	int	kbdd_downs_entries; /* # of possible entries in kbdd_downs */
150*7c478bd9Sstevel@tonic-gate 	uint_t	kbdd_downs_bytes; /* # of bytes allocated for kbdd_downs */
151*7c478bd9Sstevel@tonic-gate 	ushort_t compose_key;		/* first compose key */
152*7c478bd9Sstevel@tonic-gate 	ushort_t fltaccent_entry;	/* floating accent keymap entry */
153*7c478bd9Sstevel@tonic-gate 	char	led_state;		/* current state of LEDs */
154*7c478bd9Sstevel@tonic-gate };
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate #define	KBD_OPEN	0x00000001 /* keyboard is open for business */
157*7c478bd9Sstevel@tonic-gate #define	KBD_IOCWAIT	0x00000002 /* "open" waiting for "ioctl" to finish */
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate #define	NO_HARD_RESET	0		/* don't do hard reset */
160*7c478bd9Sstevel@tonic-gate #define	HARD_RESET	1		/* do hard reset */
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate /*
164*7c478bd9Sstevel@tonic-gate  * Constants setup during the first open of a kbd (so that they can be patched
165*7c478bd9Sstevel@tonic-gate  * for debugging purposes).
166*7c478bd9Sstevel@tonic-gate  */
167*7c478bd9Sstevel@tonic-gate static int kbd_repeatrate;
168*7c478bd9Sstevel@tonic-gate static int kbd_repeatdelay;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate static int kbd_overflow_cnt;	/* Number of times kbd overflowed input q */
171*7c478bd9Sstevel@tonic-gate static int kbd_overflow_msg = 1; /* Whether to print message on q overflow */
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate #ifdef	KBD_DEBUG
174*7c478bd9Sstevel@tonic-gate int	kbd_debug = 0;
175*7c478bd9Sstevel@tonic-gate int	kbd_ra_debug = 0;
176*7c478bd9Sstevel@tonic-gate int	kbd_raw_debug = 0;
177*7c478bd9Sstevel@tonic-gate int	kbd_rpt_debug = 0;
178*7c478bd9Sstevel@tonic-gate int	kbd_input_debug = 0;
179*7c478bd9Sstevel@tonic-gate #endif	/* KBD_DEBUG */
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate static int	kbdopen(queue_t *, dev_t *, int, int, cred_t *);
182*7c478bd9Sstevel@tonic-gate static int	kbdclose(queue_t *, int, cred_t *);
183*7c478bd9Sstevel@tonic-gate static void	kbdwput(queue_t *, mblk_t *);
184*7c478bd9Sstevel@tonic-gate static void	kbdrput(queue_t *, mblk_t *);
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate static struct module_info kbdmiinfo = {
187*7c478bd9Sstevel@tonic-gate 	0,
188*7c478bd9Sstevel@tonic-gate 	"kb",
189*7c478bd9Sstevel@tonic-gate 	0,
190*7c478bd9Sstevel@tonic-gate 	INFPSZ,
191*7c478bd9Sstevel@tonic-gate 	2048,
192*7c478bd9Sstevel@tonic-gate 	128
193*7c478bd9Sstevel@tonic-gate };
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate static struct qinit kbdrinit = {
196*7c478bd9Sstevel@tonic-gate 	(int (*)())kbdrput,
197*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
198*7c478bd9Sstevel@tonic-gate 	kbdopen,
199*7c478bd9Sstevel@tonic-gate 	kbdclose,
200*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
201*7c478bd9Sstevel@tonic-gate 	&kbdmiinfo
202*7c478bd9Sstevel@tonic-gate };
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate static struct module_info kbdmoinfo = {
205*7c478bd9Sstevel@tonic-gate 	0,
206*7c478bd9Sstevel@tonic-gate 	"kb",
207*7c478bd9Sstevel@tonic-gate 	0,
208*7c478bd9Sstevel@tonic-gate 	INFPSZ,
209*7c478bd9Sstevel@tonic-gate 	2048,
210*7c478bd9Sstevel@tonic-gate 	128
211*7c478bd9Sstevel@tonic-gate };
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate static struct qinit kbdwinit = {
214*7c478bd9Sstevel@tonic-gate 	(int (*)())kbdwput,
215*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
216*7c478bd9Sstevel@tonic-gate 	kbdopen,
217*7c478bd9Sstevel@tonic-gate 	kbdclose,
218*7c478bd9Sstevel@tonic-gate 	(int (*)())NULL,
219*7c478bd9Sstevel@tonic-gate 	&kbdmoinfo
220*7c478bd9Sstevel@tonic-gate };
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate static struct streamtab kbd_info = {
223*7c478bd9Sstevel@tonic-gate 	&kbdrinit,
224*7c478bd9Sstevel@tonic-gate 	&kbdwinit,
225*7c478bd9Sstevel@tonic-gate 	NULL,
226*7c478bd9Sstevel@tonic-gate 	NULL,
227*7c478bd9Sstevel@tonic-gate };
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate static void	kbdreioctl(void *);
230*7c478bd9Sstevel@tonic-gate static void	kbdioctl(queue_t *, mblk_t *);
231*7c478bd9Sstevel@tonic-gate static void	kbdflush(struct kbddata *);
232*7c478bd9Sstevel@tonic-gate static void	kbduse(struct kbddata *, unsigned);
233*7c478bd9Sstevel@tonic-gate static void	kbdsetled(struct kbddata *);
234*7c478bd9Sstevel@tonic-gate static void	kbdcmd(queue_t *, char);
235*7c478bd9Sstevel@tonic-gate static void	kbdreset(struct kbddata *, uint_t);
236*7c478bd9Sstevel@tonic-gate static int	kbdsetkey(struct kbddata *, struct kiockey *,  cred_t *);
237*7c478bd9Sstevel@tonic-gate static int	kbdgetkey(struct kbddata *, struct kiockey *);
238*7c478bd9Sstevel@tonic-gate static int	kbdskey(struct kbddata *, struct kiockeymap *,  cred_t *);
239*7c478bd9Sstevel@tonic-gate static int	kbdgkey(struct kbddata *, struct kiockeymap *);
240*7c478bd9Sstevel@tonic-gate static void	kbdlayouttimeout(void *);
241*7c478bd9Sstevel@tonic-gate static void	kbdinput(struct kbddata *, unsigned);
242*7c478bd9Sstevel@tonic-gate static void	kbdid(struct kbddata *, int);
243*7c478bd9Sstevel@tonic-gate static struct	keymap *settable(struct kbddata *, uint_t);
244*7c478bd9Sstevel@tonic-gate static void	kbdrpt(void *);
245*7c478bd9Sstevel@tonic-gate static void	kbdcancelrpt(struct kbddata *);
246*7c478bd9Sstevel@tonic-gate static void	kbdtranslate(struct kbddata *, unsigned, queue_t *);
247*7c478bd9Sstevel@tonic-gate static int	kbd_do_compose(ushort_t, ushort_t, ushort_t *);
248*7c478bd9Sstevel@tonic-gate static void	kbd_send_esc_event(char, struct kbddata *);
249*7c478bd9Sstevel@tonic-gate char		*strsetwithdecimal(char *, uint_t, uint_t);
250*7c478bd9Sstevel@tonic-gate static void	kbdkeypressed(struct kbddata *, uchar_t, Firm_event *,
251*7c478bd9Sstevel@tonic-gate 								ushort_t);
252*7c478bd9Sstevel@tonic-gate static void	kbdqueuepress(struct kbddata *, uchar_t, Firm_event *);
253*7c478bd9Sstevel@tonic-gate static void	kbdkeyreleased(struct kbddata *, uchar_t);
254*7c478bd9Sstevel@tonic-gate static void	kbdreleaseall(struct kbddata *);
255*7c478bd9Sstevel@tonic-gate static void	kbdputcode(uint_t, queue_t *);
256*7c478bd9Sstevel@tonic-gate static void	kbdputbuf(char *, queue_t *);
257*7c478bd9Sstevel@tonic-gate static void	kbdqueueevent(struct kbddata *, Firm_event *);
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate /*
260*7c478bd9Sstevel@tonic-gate  * Dummy qbufcall callback routine used by open and close.
261*7c478bd9Sstevel@tonic-gate  * The framework will wake up qwait_sig when we return from
262*7c478bd9Sstevel@tonic-gate  * this routine (as part of leaving the perimeters.)
263*7c478bd9Sstevel@tonic-gate  * (The framework enters the perimeters before calling the qbufcall() callback
264*7c478bd9Sstevel@tonic-gate  * and leaves the perimeters after the callback routine has executed. The
265*7c478bd9Sstevel@tonic-gate  * framework performs an implicit wakeup of any thread in qwait/qwait_sig
266*7c478bd9Sstevel@tonic-gate  * when it leaves the perimeter. See qwait(9E).)
267*7c478bd9Sstevel@tonic-gate  */
268*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
269*7c478bd9Sstevel@tonic-gate static void dummy_callback(void *arg)
270*7c478bd9Sstevel@tonic-gate {}
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate /*
274*7c478bd9Sstevel@tonic-gate  * Open a keyboard.
275*7c478bd9Sstevel@tonic-gate  * Ttyopen sets line characteristics
276*7c478bd9Sstevel@tonic-gate  */
277*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
278*7c478bd9Sstevel@tonic-gate static int
279*7c478bd9Sstevel@tonic-gate kbdopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
280*7c478bd9Sstevel@tonic-gate {
281*7c478bd9Sstevel@tonic-gate 	register int  error;
282*7c478bd9Sstevel@tonic-gate 	register struct	kbddata *kbdd;
283*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
284*7c478bd9Sstevel@tonic-gate 	mblk_t *datap;
285*7c478bd9Sstevel@tonic-gate 	register struct iocblk *iocb;
286*7c478bd9Sstevel@tonic-gate 	register struct termios *cb;
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	/* Set these up only once so that they could be changed from adb */
289*7c478bd9Sstevel@tonic-gate 	if (!kbd_repeatrate) {
290*7c478bd9Sstevel@tonic-gate 		kbd_repeatrate = (hz+29)/30;
291*7c478bd9Sstevel@tonic-gate 		kbd_repeatdelay = hz/2;
292*7c478bd9Sstevel@tonic-gate 	}
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	if (q->q_ptr != NULL)
295*7c478bd9Sstevel@tonic-gate 		return (0);		/* already attached */
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	/*
298*7c478bd9Sstevel@tonic-gate 	 * Only allow open requests to succeed for privileged users.  This
299*7c478bd9Sstevel@tonic-gate 	 * necessary to prevent users from pushing the "kb" module again
300*7c478bd9Sstevel@tonic-gate 	 * on the stream associated with /dev/kbd.
301*7c478bd9Sstevel@tonic-gate 	 */
302*7c478bd9Sstevel@tonic-gate 	if (secpolicy_console(crp) != 0) {
303*7c478bd9Sstevel@tonic-gate 		return (EPERM);
304*7c478bd9Sstevel@tonic-gate 	}
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	switch (sflag) {
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	case MODOPEN:
310*7c478bd9Sstevel@tonic-gate 		break;
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	case CLONEOPEN:
313*7c478bd9Sstevel@tonic-gate 		return (EINVAL);	/* No Bozos! */
314*7c478bd9Sstevel@tonic-gate 	}
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	/* allocate keyboard */
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	kbdd = kmem_zalloc(sizeof (struct kbddata), KM_SLEEP);
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	/*
322*7c478bd9Sstevel@tonic-gate 	 * Set up queue pointers, so that the "put" procedure will accept
323*7c478bd9Sstevel@tonic-gate 	 * the reply to the "ioctl" message we send down.
324*7c478bd9Sstevel@tonic-gate 	 */
325*7c478bd9Sstevel@tonic-gate 	q->q_ptr = kbdd;
326*7c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = kbdd;
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	qprocson(q);
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	/*
331*7c478bd9Sstevel@tonic-gate 	 * Setup tty modes.
332*7c478bd9Sstevel@tonic-gate 	 */
333*7c478bd9Sstevel@tonic-gate 	while ((mp = mkiocb(TCSETSF)) == NULL) {
334*7c478bd9Sstevel@tonic-gate 		timeout_id_t id = qbufcall(q, sizeof (struct iocblk), BPRI_HI,
335*7c478bd9Sstevel@tonic-gate 		    dummy_callback, NULL);
336*7c478bd9Sstevel@tonic-gate 		if (!qwait_sig(q)) {
337*7c478bd9Sstevel@tonic-gate 			qunbufcall(q, id);
338*7c478bd9Sstevel@tonic-gate 			kmem_free(kbdd, sizeof (struct kbddata));
339*7c478bd9Sstevel@tonic-gate 			qprocsoff(q);
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 			return (EINTR);
342*7c478bd9Sstevel@tonic-gate 		}
343*7c478bd9Sstevel@tonic-gate 	}
344*7c478bd9Sstevel@tonic-gate 	while ((datap = allocb(sizeof (struct termios), BPRI_HI)) ==
345*7c478bd9Sstevel@tonic-gate 		NULL) {
346*7c478bd9Sstevel@tonic-gate 		timeout_id_t id = qbufcall(q, sizeof (struct termios), BPRI_HI,
347*7c478bd9Sstevel@tonic-gate 		    dummy_callback, NULL);
348*7c478bd9Sstevel@tonic-gate 		if (!qwait_sig(q)) {
349*7c478bd9Sstevel@tonic-gate 			qunbufcall(q, id);
350*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
351*7c478bd9Sstevel@tonic-gate 			kmem_free(kbdd, sizeof (struct kbddata));
352*7c478bd9Sstevel@tonic-gate 			qprocsoff(q);
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 			return (EINTR);
355*7c478bd9Sstevel@tonic-gate 		}
356*7c478bd9Sstevel@tonic-gate 	}
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	iocb		= (struct iocblk *)mp->b_rptr;
359*7c478bd9Sstevel@tonic-gate 	iocb->ioc_count	= sizeof (struct termios);
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	cb = (struct termios *)datap->b_rptr;
362*7c478bd9Sstevel@tonic-gate 	cb->c_iflag = 0;
363*7c478bd9Sstevel@tonic-gate 	cb->c_oflag = 0;
364*7c478bd9Sstevel@tonic-gate 	cb->c_cflag = CREAD|CS8|B1200;
365*7c478bd9Sstevel@tonic-gate 	cb->c_lflag = 0;
366*7c478bd9Sstevel@tonic-gate 	bzero(cb->c_cc, NCCS);
367*7c478bd9Sstevel@tonic-gate 	datap->b_wptr += sizeof (struct termios);
368*7c478bd9Sstevel@tonic-gate 	mp->b_cont = datap;
369*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_flags |= KBD_IOCWAIT;	/* indicate that we're */
370*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_iocid = iocb->ioc_id;	/* waiting for this response */
371*7c478bd9Sstevel@tonic-gate 	putnext(WR(q), mp);
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	/*
374*7c478bd9Sstevel@tonic-gate 	 * Now wait for it.  Let our read queue put routine wake us up
375*7c478bd9Sstevel@tonic-gate 	 * when it arrives.
376*7c478bd9Sstevel@tonic-gate 	 */
377*7c478bd9Sstevel@tonic-gate 	while (kbdd->kbdd_flags & KBD_IOCWAIT) {
378*7c478bd9Sstevel@tonic-gate 		if (!qwait_sig(q)) {
379*7c478bd9Sstevel@tonic-gate 			error = EINTR;
380*7c478bd9Sstevel@tonic-gate 			goto error;
381*7c478bd9Sstevel@tonic-gate 		}
382*7c478bd9Sstevel@tonic-gate 	}
383*7c478bd9Sstevel@tonic-gate 	if ((error = kbdd->kbdd_iocerror) != 0)
384*7c478bd9Sstevel@tonic-gate 		goto error;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	/*
387*7c478bd9Sstevel@tonic-gate 	 * Set up private data.
388*7c478bd9Sstevel@tonic-gate 	 */
389*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_readq = q;
390*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_writeq = WR(q);
391*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_iocpending = NULL;
392*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_translatable = TR_CAN;
393*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_translate = TR_ASCII;
394*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_compat = 1;
395*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_ascii_addr = ASCII_FIRST;
396*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_top_addr = TOP_FIRST;
397*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_vkey_addr = VKEY_FIRST;
398*7c478bd9Sstevel@tonic-gate 	/* Allocate dynamic memory for downs table */
399*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_downs_entries = kbd_downs_size;
400*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_downs_bytes = kbd_downs_size * sizeof (Key_event);
401*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_downs = kmem_alloc(kbdd->kbdd_downs_bytes, KM_SLEEP);
402*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_flags = KBD_OPEN;
403*7c478bd9Sstevel@tonic-gate 	kbdd->led_state = 0;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	/*
406*7c478bd9Sstevel@tonic-gate 	 * Reset kbd.
407*7c478bd9Sstevel@tonic-gate 	 */
408*7c478bd9Sstevel@tonic-gate 	kbdreset(kbdd, HARD_RESET);
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	return (0);
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate error:
413*7c478bd9Sstevel@tonic-gate 	qprocsoff(q);
414*7c478bd9Sstevel@tonic-gate 	kmem_free(kbdd, sizeof (struct kbddata));
415*7c478bd9Sstevel@tonic-gate 	return (error);
416*7c478bd9Sstevel@tonic-gate }
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate /*
419*7c478bd9Sstevel@tonic-gate  * Close a keyboard.
420*7c478bd9Sstevel@tonic-gate  */
421*7c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
422*7c478bd9Sstevel@tonic-gate static int
423*7c478bd9Sstevel@tonic-gate kbdclose(register queue_t *q, int flag, cred_t *crp)
424*7c478bd9Sstevel@tonic-gate {
425*7c478bd9Sstevel@tonic-gate 	register struct kbddata *kbdd = (struct kbddata *)q->q_ptr;
426*7c478bd9Sstevel@tonic-gate 	register mblk_t *mp;
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	qprocsoff(q);
429*7c478bd9Sstevel@tonic-gate 	/*
430*7c478bd9Sstevel@tonic-gate 	 * Since we're about to destroy our private data, turn off
431*7c478bd9Sstevel@tonic-gate 	 * our open flag first, so we don't accept any more input
432*7c478bd9Sstevel@tonic-gate 	 * and try to use that data.
433*7c478bd9Sstevel@tonic-gate 	 */
434*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_flags = 0;
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 	if ((mp = kbdd->kbdd_replypending) != NULL) {
437*7c478bd9Sstevel@tonic-gate 		/*
438*7c478bd9Sstevel@tonic-gate 		 * There was a KIOCLAYOUT pending; presumably, it timed out.
439*7c478bd9Sstevel@tonic-gate 		 * Throw the reply away.
440*7c478bd9Sstevel@tonic-gate 		 */
441*7c478bd9Sstevel@tonic-gate 		kbdd->kbdd_replypending = NULL;
442*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
443*7c478bd9Sstevel@tonic-gate 	}
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	/* clear all timeouts */
446*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_bufcallid)
447*7c478bd9Sstevel@tonic-gate 		qunbufcall(q, kbdd->kbdd_bufcallid);
448*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_rptid)
449*7c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, kbdd->kbdd_rptid);
450*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_layoutid)
451*7c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, kbdd->kbdd_layoutid);
452*7c478bd9Sstevel@tonic-gate 	kmem_free(kbdd->kbdd_downs, kbdd->kbdd_downs_bytes);
453*7c478bd9Sstevel@tonic-gate 	kmem_free(kbdd, sizeof (struct kbddata));
454*7c478bd9Sstevel@tonic-gate 	return (0);
455*7c478bd9Sstevel@tonic-gate }
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate /*
458*7c478bd9Sstevel@tonic-gate  * Line discipline output queue put procedure: handles M_IOCTL
459*7c478bd9Sstevel@tonic-gate  * messages.
460*7c478bd9Sstevel@tonic-gate  */
461*7c478bd9Sstevel@tonic-gate static void
462*7c478bd9Sstevel@tonic-gate kbdwput(register queue_t *q, register mblk_t *mp)
463*7c478bd9Sstevel@tonic-gate {
464*7c478bd9Sstevel@tonic-gate 	/*
465*7c478bd9Sstevel@tonic-gate 	 * Process M_FLUSH, and some M_IOCTL, messages here; pass
466*7c478bd9Sstevel@tonic-gate 	 * everything else down.
467*7c478bd9Sstevel@tonic-gate 	 */
468*7c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:
471*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
472*7c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
473*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
474*7c478bd9Sstevel@tonic-gate 			flushq(RD(q), FLUSHDATA);
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	default:
477*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);	/* pass it down the line */
478*7c478bd9Sstevel@tonic-gate 		break;
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	case M_IOCTL:
481*7c478bd9Sstevel@tonic-gate 		kbdioctl(q, mp);
482*7c478bd9Sstevel@tonic-gate 		break;
483*7c478bd9Sstevel@tonic-gate 	}
484*7c478bd9Sstevel@tonic-gate }
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate static void
488*7c478bd9Sstevel@tonic-gate kbdreioctl(void *kbdd_addr)
489*7c478bd9Sstevel@tonic-gate {
490*7c478bd9Sstevel@tonic-gate 	struct kbddata *kbdd = kbdd_addr;
491*7c478bd9Sstevel@tonic-gate 	queue_t *q;
492*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_bufcallid = 0;
495*7c478bd9Sstevel@tonic-gate 	q = kbdd->kbdd_writeq;
496*7c478bd9Sstevel@tonic-gate 	if ((mp = kbdd->kbdd_iocpending) != NULL) {
497*7c478bd9Sstevel@tonic-gate 		kbdd->kbdd_iocpending = NULL;	/* not pending any more */
498*7c478bd9Sstevel@tonic-gate 		kbdioctl(q, mp);
499*7c478bd9Sstevel@tonic-gate 	}
500*7c478bd9Sstevel@tonic-gate }
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate static void
503*7c478bd9Sstevel@tonic-gate kbdioctl(register queue_t *q, register mblk_t *mp)
504*7c478bd9Sstevel@tonic-gate {
505*7c478bd9Sstevel@tonic-gate 	register struct kbddata *kbdd = (struct kbddata *)q->q_ptr;
506*7c478bd9Sstevel@tonic-gate 	register struct iocblk *iocp;
507*7c478bd9Sstevel@tonic-gate 	register short	new_translate;
508*7c478bd9Sstevel@tonic-gate 	register Vuid_addr_probe *addr_probe;
509*7c478bd9Sstevel@tonic-gate 	register short	*addr_ptr;
510*7c478bd9Sstevel@tonic-gate 	mblk_t *datap;
511*7c478bd9Sstevel@tonic-gate 	size_t	ioctlrespsize;
512*7c478bd9Sstevel@tonic-gate 	int	err = 0;
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	case VUIDSFORMAT:
519*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
520*7c478bd9Sstevel@tonic-gate 		if (err != 0)
521*7c478bd9Sstevel@tonic-gate 			break;
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate 		new_translate = (*(int *)mp->b_cont->b_rptr == VUID_NATIVE) ?
524*7c478bd9Sstevel@tonic-gate 		    TR_ASCII : TR_EVENT;
525*7c478bd9Sstevel@tonic-gate 		if (new_translate == kbdd->kbdd_translate)
526*7c478bd9Sstevel@tonic-gate 			break;
527*7c478bd9Sstevel@tonic-gate 		kbdd->kbdd_translate = new_translate;
528*7c478bd9Sstevel@tonic-gate 		goto output_format_change;
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	case KIOCTRANS:
531*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
532*7c478bd9Sstevel@tonic-gate 		if (err != 0)
533*7c478bd9Sstevel@tonic-gate 			break;
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 		new_translate = *(int *)mp->b_cont->b_rptr;
536*7c478bd9Sstevel@tonic-gate 		if (new_translate == kbdd->kbdd_translate)
537*7c478bd9Sstevel@tonic-gate 			break;
538*7c478bd9Sstevel@tonic-gate 		kbdd->kbdd_translate = new_translate;
539*7c478bd9Sstevel@tonic-gate 		goto output_format_change;
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 	case KIOCCMD:
542*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
543*7c478bd9Sstevel@tonic-gate 		if (err != 0)
544*7c478bd9Sstevel@tonic-gate 			break;
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 		kbdcmd(q, (char)(*(int *)mp->b_cont->b_rptr));
547*7c478bd9Sstevel@tonic-gate 		break;
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 	case KIOCSLED:
550*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (uchar_t));
551*7c478bd9Sstevel@tonic-gate 		if (err != 0)
552*7c478bd9Sstevel@tonic-gate 			break;
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 		kbdd->led_state = *(uchar_t *)mp->b_cont->b_rptr;
555*7c478bd9Sstevel@tonic-gate 		kbdsetled(kbdd);
556*7c478bd9Sstevel@tonic-gate 		break;
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 	case KIOCGLED:
559*7c478bd9Sstevel@tonic-gate 		if ((datap = allocb(sizeof (uchar_t), BPRI_HI)) == NULL) {
560*7c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
561*7c478bd9Sstevel@tonic-gate 			goto allocfailure;
562*7c478bd9Sstevel@tonic-gate 		}
563*7c478bd9Sstevel@tonic-gate 		*(uchar_t *)datap->b_wptr = kbdd->led_state;
564*7c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (uchar_t);
565*7c478bd9Sstevel@tonic-gate 		if (mp->b_cont)  /* free msg to prevent memory leak */
566*7c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
567*7c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
568*7c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (uchar_t);
569*7c478bd9Sstevel@tonic-gate 		break;
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 	case VUIDGFORMAT:
572*7c478bd9Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
573*7c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
574*7c478bd9Sstevel@tonic-gate 			goto allocfailure;
575*7c478bd9Sstevel@tonic-gate 		}
576*7c478bd9Sstevel@tonic-gate 		*(int *)datap->b_wptr =
577*7c478bd9Sstevel@tonic-gate 		    (kbdd->kbdd_translate == TR_EVENT ||
578*7c478bd9Sstevel@tonic-gate 		    kbdd->kbdd_translate == TR_UNTRANS_EVENT) ?
579*7c478bd9Sstevel@tonic-gate 			VUID_FIRM_EVENT: VUID_NATIVE;
580*7c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
581*7c478bd9Sstevel@tonic-gate 		if (mp->b_cont)  /* free msg to prevent memory leak */
582*7c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
583*7c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
584*7c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
585*7c478bd9Sstevel@tonic-gate 		break;
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 	case KIOCGTRANS:
588*7c478bd9Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
589*7c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
590*7c478bd9Sstevel@tonic-gate 			goto allocfailure;
591*7c478bd9Sstevel@tonic-gate 		}
592*7c478bd9Sstevel@tonic-gate 		*(int *)datap->b_wptr = kbdd->kbdd_translate;
593*7c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
594*7c478bd9Sstevel@tonic-gate 		if (mp->b_cont)  /* free msg to prevent memory leak */
595*7c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
596*7c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
597*7c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
598*7c478bd9Sstevel@tonic-gate 		break;
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	case VUIDSADDR:
601*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (Vuid_addr_probe));
602*7c478bd9Sstevel@tonic-gate 		if (err != 0)
603*7c478bd9Sstevel@tonic-gate 			break;
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 		addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
606*7c478bd9Sstevel@tonic-gate 		switch (addr_probe->base) {
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 		case ASCII_FIRST:
609*7c478bd9Sstevel@tonic-gate 			addr_ptr = &kbdd->kbdd_ascii_addr;
610*7c478bd9Sstevel@tonic-gate 			break;
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 		case TOP_FIRST:
613*7c478bd9Sstevel@tonic-gate 			addr_ptr = &kbdd->kbdd_top_addr;
614*7c478bd9Sstevel@tonic-gate 			break;
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 		case VKEY_FIRST:
617*7c478bd9Sstevel@tonic-gate 			addr_ptr = &kbdd->kbdd_vkey_addr;
618*7c478bd9Sstevel@tonic-gate 			break;
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 		default:
621*7c478bd9Sstevel@tonic-gate 			err = ENODEV;
622*7c478bd9Sstevel@tonic-gate 		}
623*7c478bd9Sstevel@tonic-gate 		if ((err == 0) && (*addr_ptr != addr_probe->data.next)) {
624*7c478bd9Sstevel@tonic-gate 			*addr_ptr = addr_probe->data.next;
625*7c478bd9Sstevel@tonic-gate 			goto output_format_change;
626*7c478bd9Sstevel@tonic-gate 		}
627*7c478bd9Sstevel@tonic-gate 		break;
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	case VUIDGADDR:
630*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (Vuid_addr_probe));
631*7c478bd9Sstevel@tonic-gate 		if (err != 0)
632*7c478bd9Sstevel@tonic-gate 			break;
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 		addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
635*7c478bd9Sstevel@tonic-gate 		switch (addr_probe->base) {
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 		case ASCII_FIRST:
638*7c478bd9Sstevel@tonic-gate 			addr_probe->data.current = kbdd->kbdd_ascii_addr;
639*7c478bd9Sstevel@tonic-gate 			break;
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 		case TOP_FIRST:
642*7c478bd9Sstevel@tonic-gate 			addr_probe->data.current = kbdd->kbdd_top_addr;
643*7c478bd9Sstevel@tonic-gate 			break;
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 		case VKEY_FIRST:
646*7c478bd9Sstevel@tonic-gate 			addr_probe->data.current = kbdd->kbdd_vkey_addr;
647*7c478bd9Sstevel@tonic-gate 			break;
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 		default:
650*7c478bd9Sstevel@tonic-gate 			err = ENODEV;
651*7c478bd9Sstevel@tonic-gate 		}
652*7c478bd9Sstevel@tonic-gate 		break;
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 	case KIOCTRANSABLE:
655*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
656*7c478bd9Sstevel@tonic-gate 		if (err != 0)
657*7c478bd9Sstevel@tonic-gate 			break;
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 		if (kbdd->kbdd_translatable != *(int *)mp->b_cont->b_rptr) {
660*7c478bd9Sstevel@tonic-gate 			kbdd->kbdd_translatable = *(int *)mp->b_cont->b_rptr;
661*7c478bd9Sstevel@tonic-gate 			kbdreset(kbdd, HARD_RESET);
662*7c478bd9Sstevel@tonic-gate 			goto output_format_change;
663*7c478bd9Sstevel@tonic-gate 		}
664*7c478bd9Sstevel@tonic-gate 		break;
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	case KIOCGTRANSABLE:
667*7c478bd9Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
668*7c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
669*7c478bd9Sstevel@tonic-gate 			goto allocfailure;
670*7c478bd9Sstevel@tonic-gate 		}
671*7c478bd9Sstevel@tonic-gate 		*(int *)datap->b_wptr = kbdd->kbdd_translatable;
672*7c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
673*7c478bd9Sstevel@tonic-gate 		if (mp->b_cont)  /* free msg to prevent memory leak */
674*7c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
675*7c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
676*7c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
677*7c478bd9Sstevel@tonic-gate 		break;
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	case KIOCSCOMPAT:
680*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
681*7c478bd9Sstevel@tonic-gate 		if (err != 0)
682*7c478bd9Sstevel@tonic-gate 			break;
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 		kbdd->kbdd_compat = *(int *)mp->b_cont->b_rptr;
685*7c478bd9Sstevel@tonic-gate 		break;
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 	case KIOCGCOMPAT:
688*7c478bd9Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
689*7c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
690*7c478bd9Sstevel@tonic-gate 			goto allocfailure;
691*7c478bd9Sstevel@tonic-gate 		}
692*7c478bd9Sstevel@tonic-gate 		*(int *)datap->b_wptr = kbdd->kbdd_compat;
693*7c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
694*7c478bd9Sstevel@tonic-gate 		if (mp->b_cont)  /* free msg to prevent memory leak */
695*7c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
696*7c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
697*7c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
698*7c478bd9Sstevel@tonic-gate 		break;
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 	case KIOCSETKEY:
701*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (struct kiockey));
702*7c478bd9Sstevel@tonic-gate 		if (err != 0)
703*7c478bd9Sstevel@tonic-gate 			break;
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate 		err = kbdsetkey(kbdd, (struct kiockey *)mp->b_cont->b_rptr,
706*7c478bd9Sstevel@tonic-gate 		    iocp->ioc_cr);
707*7c478bd9Sstevel@tonic-gate 		/*
708*7c478bd9Sstevel@tonic-gate 		 * Since this only affects any subsequent key presses,
709*7c478bd9Sstevel@tonic-gate 		 * don't goto output_format_change.  One might want to
710*7c478bd9Sstevel@tonic-gate 		 * toggle the keytable entries dynamically.
711*7c478bd9Sstevel@tonic-gate 		 */
712*7c478bd9Sstevel@tonic-gate 		break;
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate 	case KIOCGETKEY:
715*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (struct kiockey));
716*7c478bd9Sstevel@tonic-gate 		if (err != 0)
717*7c478bd9Sstevel@tonic-gate 			break;
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 		err = kbdgetkey(kbdd, (struct kiockey *)mp->b_cont->b_rptr);
720*7c478bd9Sstevel@tonic-gate 		break;
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate 	case KIOCSKEY:
723*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (struct kiockeymap));
724*7c478bd9Sstevel@tonic-gate 		if (err != 0)
725*7c478bd9Sstevel@tonic-gate 			break;
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 		err = kbdskey(kbdd, (struct kiockeymap *)mp->b_cont->b_rptr,
728*7c478bd9Sstevel@tonic-gate 		    iocp->ioc_cr);
729*7c478bd9Sstevel@tonic-gate 		/*
730*7c478bd9Sstevel@tonic-gate 		 * Since this only affects any subsequent key presses,
731*7c478bd9Sstevel@tonic-gate 		 * don't goto output_format_change.  One might want to
732*7c478bd9Sstevel@tonic-gate 		 * toggle the keytable entries dynamically.
733*7c478bd9Sstevel@tonic-gate 		 */
734*7c478bd9Sstevel@tonic-gate 		break;
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 	case KIOCGKEY:
737*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (struct kiockeymap));
738*7c478bd9Sstevel@tonic-gate 		if (err != 0)
739*7c478bd9Sstevel@tonic-gate 			break;
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 		err = kbdgkey(kbdd, (struct kiockeymap *)mp->b_cont->b_rptr);
742*7c478bd9Sstevel@tonic-gate 		break;
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 	case KIOCSDIRECT:
745*7c478bd9Sstevel@tonic-gate 		goto output_format_change;
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate 	case KIOCGDIRECT:
748*7c478bd9Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
749*7c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
750*7c478bd9Sstevel@tonic-gate 			goto allocfailure;
751*7c478bd9Sstevel@tonic-gate 		}
752*7c478bd9Sstevel@tonic-gate 		*(int *)datap->b_wptr = 1;	/* always direct */
753*7c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
754*7c478bd9Sstevel@tonic-gate 		if (mp->b_cont) /* free msg to prevent memory leak */
755*7c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
756*7c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
757*7c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
758*7c478bd9Sstevel@tonic-gate 		break;
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 	case KIOCTYPE:
761*7c478bd9Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
762*7c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
763*7c478bd9Sstevel@tonic-gate 			goto allocfailure;
764*7c478bd9Sstevel@tonic-gate 		}
765*7c478bd9Sstevel@tonic-gate 		*(int *)datap->b_wptr = kbdd->kbdd_state.k_id;
766*7c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
767*7c478bd9Sstevel@tonic-gate 		if (mp->b_cont) /* free msg to prevent memory leak */
768*7c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
769*7c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
770*7c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
771*7c478bd9Sstevel@tonic-gate 		break;
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 	case KIOCLAYOUT:
774*7c478bd9Sstevel@tonic-gate 		if ((datap = kbdd->kbdd_replypending) != NULL) {
775*7c478bd9Sstevel@tonic-gate 			/*
776*7c478bd9Sstevel@tonic-gate 			 * There was an earlier KIOCLAYOUT pending; presumably,
777*7c478bd9Sstevel@tonic-gate 			 * it timed out.  Throw the reply away.
778*7c478bd9Sstevel@tonic-gate 			 */
779*7c478bd9Sstevel@tonic-gate 			kbdd->kbdd_replypending = NULL;
780*7c478bd9Sstevel@tonic-gate 			freemsg(datap);
781*7c478bd9Sstevel@tonic-gate 		}
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 		if (kbdd->kbdd_state.k_id == KB_SUN4 ||
784*7c478bd9Sstevel@tonic-gate 		    kbdd->kbdd_state.k_id == KB_PC) {
785*7c478bd9Sstevel@tonic-gate 			if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
786*7c478bd9Sstevel@tonic-gate 				ioctlrespsize = sizeof (int);
787*7c478bd9Sstevel@tonic-gate 				goto allocfailure;
788*7c478bd9Sstevel@tonic-gate 			}
789*7c478bd9Sstevel@tonic-gate 			iocp->ioc_rval = 0;
790*7c478bd9Sstevel@tonic-gate 			iocp->ioc_error = 0;	/* brain rot */
791*7c478bd9Sstevel@tonic-gate 			iocp->ioc_count = sizeof (int);
792*7c478bd9Sstevel@tonic-gate 			if (mp->b_cont)   /* free msg to prevent memory leak */
793*7c478bd9Sstevel@tonic-gate 				freemsg(mp->b_cont);
794*7c478bd9Sstevel@tonic-gate 			mp->b_cont = datap;
795*7c478bd9Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
796*7c478bd9Sstevel@tonic-gate 			kbdd->kbdd_replypending = mp;
797*7c478bd9Sstevel@tonic-gate 			kbdcmd(q, (char)KBD_CMD_GETLAYOUT);
798*7c478bd9Sstevel@tonic-gate 			if (kbdd->kbdd_layoutid)
799*7c478bd9Sstevel@tonic-gate 				(void) quntimeout(q, kbdd->kbdd_layoutid);
800*7c478bd9Sstevel@tonic-gate 			kbdd->kbdd_layoutid = qtimeout(q, kbdlayouttimeout,
801*7c478bd9Sstevel@tonic-gate 			    kbdd, hz / 5);
802*7c478bd9Sstevel@tonic-gate 			return;		/* wait for reply from keyboard */
803*7c478bd9Sstevel@tonic-gate 		} else {
804*7c478bd9Sstevel@tonic-gate 			/*
805*7c478bd9Sstevel@tonic-gate 			 * Not a Type 4 keyboard; return an immediate error.
806*7c478bd9Sstevel@tonic-gate 			 */
807*7c478bd9Sstevel@tonic-gate 			err = EINVAL;
808*7c478bd9Sstevel@tonic-gate 			break;
809*7c478bd9Sstevel@tonic-gate 		}
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate 	case KIOCGRPTDELAY:
812*7c478bd9Sstevel@tonic-gate 		/*
813*7c478bd9Sstevel@tonic-gate 		 * Report the autorepeat delay, unit in millisecond
814*7c478bd9Sstevel@tonic-gate 		 */
815*7c478bd9Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
816*7c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
817*7c478bd9Sstevel@tonic-gate 			goto allocfailure;
818*7c478bd9Sstevel@tonic-gate 		}
819*7c478bd9Sstevel@tonic-gate 		*(int *)datap->b_wptr = TICK_TO_MSEC(kbd_repeatdelay);
820*7c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
821*7c478bd9Sstevel@tonic-gate 
822*7c478bd9Sstevel@tonic-gate 		/* free msg to prevent memory leak */
823*7c478bd9Sstevel@tonic-gate 		if (mp->b_cont != NULL)
824*7c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
825*7c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
826*7c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
827*7c478bd9Sstevel@tonic-gate 		break;
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 	case KIOCSRPTDELAY:
830*7c478bd9Sstevel@tonic-gate 		/*
831*7c478bd9Sstevel@tonic-gate 		 * Set the autorepeat delay
832*7c478bd9Sstevel@tonic-gate 		 */
833*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 		if (err != 0)
836*7c478bd9Sstevel@tonic-gate 			break;
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 		/* validate the input */
839*7c478bd9Sstevel@tonic-gate 		if (*(int *)mp->b_cont->b_rptr < KIOCRPTDELAY_MIN) {
840*7c478bd9Sstevel@tonic-gate 			err = EINVAL;
841*7c478bd9Sstevel@tonic-gate 			break;
842*7c478bd9Sstevel@tonic-gate 		}
843*7c478bd9Sstevel@tonic-gate 		kbd_repeatdelay = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
844*7c478bd9Sstevel@tonic-gate 		if (kbd_repeatdelay <= 0)
845*7c478bd9Sstevel@tonic-gate 			kbd_repeatdelay = 1;
846*7c478bd9Sstevel@tonic-gate 		break;
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate 	case KIOCGRPTRATE:
849*7c478bd9Sstevel@tonic-gate 		/*
850*7c478bd9Sstevel@tonic-gate 		 * Report the autorepeat rate
851*7c478bd9Sstevel@tonic-gate 		 */
852*7c478bd9Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
853*7c478bd9Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
854*7c478bd9Sstevel@tonic-gate 			goto allocfailure;
855*7c478bd9Sstevel@tonic-gate 		}
856*7c478bd9Sstevel@tonic-gate 		*(int *)datap->b_wptr = TICK_TO_MSEC(kbd_repeatrate);
857*7c478bd9Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 		/* free msg to prevent memory leak */
860*7c478bd9Sstevel@tonic-gate 		if (mp->b_cont != NULL)
861*7c478bd9Sstevel@tonic-gate 			freemsg(mp->b_cont);
862*7c478bd9Sstevel@tonic-gate 		mp->b_cont = datap;
863*7c478bd9Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
864*7c478bd9Sstevel@tonic-gate 		break;
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	case KIOCSRPTRATE:
867*7c478bd9Sstevel@tonic-gate 		/*
868*7c478bd9Sstevel@tonic-gate 		 * Set the autorepeat rate
869*7c478bd9Sstevel@tonic-gate 		 */
870*7c478bd9Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 		if (err != 0)
873*7c478bd9Sstevel@tonic-gate 			break;
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 		/* validate the input */
876*7c478bd9Sstevel@tonic-gate 		if (*(int *)mp->b_cont->b_rptr < KIOCRPTRATE_MIN) {
877*7c478bd9Sstevel@tonic-gate 			err = EINVAL;
878*7c478bd9Sstevel@tonic-gate 			break;
879*7c478bd9Sstevel@tonic-gate 		}
880*7c478bd9Sstevel@tonic-gate 		kbd_repeatrate = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
881*7c478bd9Sstevel@tonic-gate 		if (kbd_repeatrate <= 0)
882*7c478bd9Sstevel@tonic-gate 			kbd_repeatrate = 1;
883*7c478bd9Sstevel@tonic-gate 		break;
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 	default:
886*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);	/* pass it down the line */
887*7c478bd9Sstevel@tonic-gate 		return;
888*7c478bd9Sstevel@tonic-gate 	}
889*7c478bd9Sstevel@tonic-gate 	goto done;
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate output_format_change:
892*7c478bd9Sstevel@tonic-gate 	kbdflush(kbdd);
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate done:
895*7c478bd9Sstevel@tonic-gate 	if (err != 0) {
896*7c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
897*7c478bd9Sstevel@tonic-gate 		iocp->ioc_error = err;
898*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
899*7c478bd9Sstevel@tonic-gate 	} else {
900*7c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
901*7c478bd9Sstevel@tonic-gate 		iocp->ioc_error = 0;	/* brain rot */
902*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
903*7c478bd9Sstevel@tonic-gate 	}
904*7c478bd9Sstevel@tonic-gate 	qreply(q, mp);
905*7c478bd9Sstevel@tonic-gate 	return;
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate allocfailure:
908*7c478bd9Sstevel@tonic-gate 	/*
909*7c478bd9Sstevel@tonic-gate 	 * We needed to allocate something to handle this "ioctl", but
910*7c478bd9Sstevel@tonic-gate 	 * couldn't; save this "ioctl" and arrange to get called back when
911*7c478bd9Sstevel@tonic-gate 	 * it's more likely that we can get what we need.
912*7c478bd9Sstevel@tonic-gate 	 * If there's already one being saved, throw it out, since it
913*7c478bd9Sstevel@tonic-gate 	 * must have timed out.
914*7c478bd9Sstevel@tonic-gate 	 */
915*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_iocpending != NULL)
916*7c478bd9Sstevel@tonic-gate 		freemsg(kbdd->kbdd_iocpending);
917*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_iocpending = mp;
918*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_bufcallid)
919*7c478bd9Sstevel@tonic-gate 		qunbufcall(q, kbdd->kbdd_bufcallid);
920*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_bufcallid = qbufcall(q, ioctlrespsize, BPRI_HI,
921*7c478bd9Sstevel@tonic-gate 	    kbdreioctl, kbdd);
922*7c478bd9Sstevel@tonic-gate }
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate static void
925*7c478bd9Sstevel@tonic-gate kbdflush(register struct kbddata *kbdd)
926*7c478bd9Sstevel@tonic-gate {
927*7c478bd9Sstevel@tonic-gate 	register queue_t *q;
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate 	/* Flush pending data already sent upstream */
930*7c478bd9Sstevel@tonic-gate 	if ((q = kbdd->kbdd_readq) != NULL && q->q_next != NULL)
931*7c478bd9Sstevel@tonic-gate 		(void) putnextctl1(q, M_FLUSH, FLUSHR);
932*7c478bd9Sstevel@tonic-gate 	/* Flush pending ups */
933*7c478bd9Sstevel@tonic-gate 	bzero(kbdd->kbdd_downs, kbdd->kbdd_downs_bytes);
934*7c478bd9Sstevel@tonic-gate 	kbdcancelrpt(kbdd);
935*7c478bd9Sstevel@tonic-gate }
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate /*
938*7c478bd9Sstevel@tonic-gate  * Pass keycode upstream, either translated or untranslated.
939*7c478bd9Sstevel@tonic-gate  */
940*7c478bd9Sstevel@tonic-gate static void
941*7c478bd9Sstevel@tonic-gate kbduse(register struct kbddata *kbdd, unsigned keycode)
942*7c478bd9Sstevel@tonic-gate {
943*7c478bd9Sstevel@tonic-gate 	register queue_t *readq;
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate #ifdef	KBD_DEBUG
946*7c478bd9Sstevel@tonic-gate 	if (kbd_input_debug) printf("KBD USE key=%d\n", keycode);
947*7c478bd9Sstevel@tonic-gate #endif
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 	if ((readq = kbdd->kbdd_readq) == NULL)
950*7c478bd9Sstevel@tonic-gate 		return;
951*7c478bd9Sstevel@tonic-gate 	if (!kbdd->kbdd_translatable ||
952*7c478bd9Sstevel@tonic-gate 	    kbdd->kbdd_translate == TR_NONE)
953*7c478bd9Sstevel@tonic-gate 		kbdputcode(keycode, readq);
954*7c478bd9Sstevel@tonic-gate 	else
955*7c478bd9Sstevel@tonic-gate 		kbdtranslate(kbdd, keycode, readq);
956*7c478bd9Sstevel@tonic-gate }
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate /*
959*7c478bd9Sstevel@tonic-gate  * kbdclick is used to remember the current click value of the
960*7c478bd9Sstevel@tonic-gate  * Sun-3 keyboard.  This brain damaged keyboard will reset the
961*7c478bd9Sstevel@tonic-gate  * clicking to the "default" value after a reset command and
962*7c478bd9Sstevel@tonic-gate  * there is no way to read out the current click value.  We
963*7c478bd9Sstevel@tonic-gate  * cannot send a click command immediately after the reset
964*7c478bd9Sstevel@tonic-gate  * command or the keyboard gets screwed up.  So we wait until
965*7c478bd9Sstevel@tonic-gate  * we get the ID byte before we send back the click command.
966*7c478bd9Sstevel@tonic-gate  * Unfortunately, this means that there is a small window
967*7c478bd9Sstevel@tonic-gate  * where the keyboard can click when it really shouldn't be.
968*7c478bd9Sstevel@tonic-gate  * A value of -1 means that kbdclick has not been initialized yet.
969*7c478bd9Sstevel@tonic-gate  */
970*7c478bd9Sstevel@tonic-gate static int kbdclick = -1;
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate /*
973*7c478bd9Sstevel@tonic-gate  * Send command byte to keyboard, if you can.
974*7c478bd9Sstevel@tonic-gate  */
975*7c478bd9Sstevel@tonic-gate static void
976*7c478bd9Sstevel@tonic-gate kbdcmd(register queue_t *q, char cmd)
977*7c478bd9Sstevel@tonic-gate {
978*7c478bd9Sstevel@tonic-gate 	register mblk_t *bp;
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 	if (canput(q)) {
981*7c478bd9Sstevel@tonic-gate 		if ((bp = allocb(1, BPRI_MED)) == NULL)
982*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
983*7c478bd9Sstevel@tonic-gate 				"kbdcmd: Can't allocate block for command");
984*7c478bd9Sstevel@tonic-gate 		else {
985*7c478bd9Sstevel@tonic-gate 			*bp->b_wptr++ = cmd;
986*7c478bd9Sstevel@tonic-gate 			putnext(q, bp);
987*7c478bd9Sstevel@tonic-gate 			if (cmd == KBD_CMD_NOCLICK)
988*7c478bd9Sstevel@tonic-gate 				kbdclick = 0;
989*7c478bd9Sstevel@tonic-gate 			else if (cmd == KBD_CMD_CLICK)
990*7c478bd9Sstevel@tonic-gate 				kbdclick = 1;
991*7c478bd9Sstevel@tonic-gate 		}
992*7c478bd9Sstevel@tonic-gate 	}
993*7c478bd9Sstevel@tonic-gate }
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate /*
996*7c478bd9Sstevel@tonic-gate  * Update the keyboard LEDs to match the current keyboard state.
997*7c478bd9Sstevel@tonic-gate  * Do this only on Type 4 keyboards; other keyboards don't support the
998*7c478bd9Sstevel@tonic-gate  * KBD_CMD_SETLED command (nor, for that matter, the appropriate LEDs).
999*7c478bd9Sstevel@tonic-gate  */
1000*7c478bd9Sstevel@tonic-gate static void
1001*7c478bd9Sstevel@tonic-gate kbdsetled(register struct kbddata *kbdd)
1002*7c478bd9Sstevel@tonic-gate {
1003*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_state.k_id == KB_SUN4 ||
1004*7c478bd9Sstevel@tonic-gate 	    kbdd->kbdd_state.k_id == KB_PC) {
1005*7c478bd9Sstevel@tonic-gate 		kbdcmd(kbdd->kbdd_writeq, KBD_CMD_SETLED);
1006*7c478bd9Sstevel@tonic-gate 		kbdcmd(kbdd->kbdd_writeq, kbdd->led_state);
1007*7c478bd9Sstevel@tonic-gate 	}
1008*7c478bd9Sstevel@tonic-gate }
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate /*
1011*7c478bd9Sstevel@tonic-gate  * Reset the keyboard
1012*7c478bd9Sstevel@tonic-gate  */
1013*7c478bd9Sstevel@tonic-gate static void
1014*7c478bd9Sstevel@tonic-gate kbdreset(register struct kbddata *kbdd, uint_t hard_reset)
1015*7c478bd9Sstevel@tonic-gate {
1016*7c478bd9Sstevel@tonic-gate 	register struct keyboardstate *k;
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 	k = &kbdd->kbdd_state;
1019*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_translatable) {
1020*7c478bd9Sstevel@tonic-gate 		k->k_idstate = KID_NONE;
1021*7c478bd9Sstevel@tonic-gate 		k->k_id = -1;
1022*7c478bd9Sstevel@tonic-gate 		k->k_state = NORMAL;
1023*7c478bd9Sstevel@tonic-gate 		if (hard_reset)
1024*7c478bd9Sstevel@tonic-gate 			kbdcmd(kbdd->kbdd_writeq, KBD_CMD_RESET);
1025*7c478bd9Sstevel@tonic-gate 	} else {
1026*7c478bd9Sstevel@tonic-gate 		bzero(k, sizeof (struct keyboardstate));
1027*7c478bd9Sstevel@tonic-gate 		k->k_id = KB_ASCII;
1028*7c478bd9Sstevel@tonic-gate 		k->k_idstate = KID_OK;
1029*7c478bd9Sstevel@tonic-gate 	}
1030*7c478bd9Sstevel@tonic-gate }
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate /*
1033*7c478bd9Sstevel@tonic-gate  * Old special codes.
1034*7c478bd9Sstevel@tonic-gate  */
1035*7c478bd9Sstevel@tonic-gate #define	OLD_SHIFTKEYS	0x80
1036*7c478bd9Sstevel@tonic-gate #define	OLD_BUCKYBITS	0x90
1037*7c478bd9Sstevel@tonic-gate #define	OLD_FUNNY	0xA0
1038*7c478bd9Sstevel@tonic-gate #define	OLD_FA_UMLAUT	0xA9
1039*7c478bd9Sstevel@tonic-gate #define	OLD_FA_CFLEX	0xAA
1040*7c478bd9Sstevel@tonic-gate #define	OLD_FA_TILDE	0xAB
1041*7c478bd9Sstevel@tonic-gate #define	OLD_FA_CEDILLA	0xAC
1042*7c478bd9Sstevel@tonic-gate #define	OLD_FA_ACUTE	0xAD
1043*7c478bd9Sstevel@tonic-gate #define	OLD_FA_GRAVE	0xAE
1044*7c478bd9Sstevel@tonic-gate #define	OLD_ISOCHAR	0xAF
1045*7c478bd9Sstevel@tonic-gate #define	OLD_STRING	0xB0
1046*7c478bd9Sstevel@tonic-gate #define	OLD_LEFTFUNC	0xC0
1047*7c478bd9Sstevel@tonic-gate #define	OLD_RIGHTFUNC	0xD0
1048*7c478bd9Sstevel@tonic-gate #define	OLD_TOPFUNC	0xE0
1049*7c478bd9Sstevel@tonic-gate #define	OLD_BOTTOMFUNC	0xF0
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate /*
1052*7c478bd9Sstevel@tonic-gate  * Map old special codes to new ones.
1053*7c478bd9Sstevel@tonic-gate  * Indexed by ((old special code) >> 4) & 0x07; add (old special code) & 0x0F.
1054*7c478bd9Sstevel@tonic-gate  */
1055*7c478bd9Sstevel@tonic-gate static ushort_t	special_old_to_new[] = {
1056*7c478bd9Sstevel@tonic-gate 	SHIFTKEYS,
1057*7c478bd9Sstevel@tonic-gate 	BUCKYBITS,
1058*7c478bd9Sstevel@tonic-gate 	FUNNY,
1059*7c478bd9Sstevel@tonic-gate 	STRING,
1060*7c478bd9Sstevel@tonic-gate 	LEFTFUNC,
1061*7c478bd9Sstevel@tonic-gate 	RIGHTFUNC,
1062*7c478bd9Sstevel@tonic-gate 	TOPFUNC,
1063*7c478bd9Sstevel@tonic-gate 	BOTTOMFUNC,
1064*7c478bd9Sstevel@tonic-gate };
1065*7c478bd9Sstevel@tonic-gate 
1066*7c478bd9Sstevel@tonic-gate /*
1067*7c478bd9Sstevel@tonic-gate  * Set individual keystation translation from old-style entry.
1068*7c478bd9Sstevel@tonic-gate  * TODO: Have each keyboard own own translation tables.
1069*7c478bd9Sstevel@tonic-gate  */
1070*7c478bd9Sstevel@tonic-gate static int
1071*7c478bd9Sstevel@tonic-gate kbdsetkey(register struct kbddata *kbdd, struct kiockey *key, cred_t *cr)
1072*7c478bd9Sstevel@tonic-gate {
1073*7c478bd9Sstevel@tonic-gate 	int	strtabindex, i;
1074*7c478bd9Sstevel@tonic-gate 	struct	keymap *km;
1075*7c478bd9Sstevel@tonic-gate 	register int tablemask;
1076*7c478bd9Sstevel@tonic-gate 	register ushort_t entry;
1077*7c478bd9Sstevel@tonic-gate 
1078*7c478bd9Sstevel@tonic-gate 	if (key->kio_station >= KEYMAP_SIZE)
1079*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1080*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_state.k_curkeyboard == NULL)
1081*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1082*7c478bd9Sstevel@tonic-gate 	tablemask = key->kio_tablemask;
1083*7c478bd9Sstevel@tonic-gate 	if (tablemask == KIOCABORT1) {
1084*7c478bd9Sstevel@tonic-gate 		if (secpolicy_console(cr) != 0)
1085*7c478bd9Sstevel@tonic-gate 			return (EPERM);
1086*7c478bd9Sstevel@tonic-gate 		kbdd->kbdd_state.k_curkeyboard->k_abort1 = key->kio_station;
1087*7c478bd9Sstevel@tonic-gate 		return (0);
1088*7c478bd9Sstevel@tonic-gate 	}
1089*7c478bd9Sstevel@tonic-gate 	if (tablemask == KIOCABORT2) {
1090*7c478bd9Sstevel@tonic-gate 		if (secpolicy_console(cr) != 0)
1091*7c478bd9Sstevel@tonic-gate 			return (EPERM);
1092*7c478bd9Sstevel@tonic-gate 		kbdd->kbdd_state.k_curkeyboard->k_abort2 = key->kio_station;
1093*7c478bd9Sstevel@tonic-gate 		return (0);
1094*7c478bd9Sstevel@tonic-gate 	}
1095*7c478bd9Sstevel@tonic-gate 	if ((tablemask & ALTGRAPHMASK) ||
1096*7c478bd9Sstevel@tonic-gate 	    (km = settable(kbdd, (uint_t)tablemask)) == NULL)
1097*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1098*7c478bd9Sstevel@tonic-gate 	if (key->kio_entry >= (uchar_t)OLD_STRING &&
1099*7c478bd9Sstevel@tonic-gate 	    key->kio_entry <= (uchar_t)(OLD_STRING + 15)) {
1100*7c478bd9Sstevel@tonic-gate 		strtabindex = key->kio_entry - OLD_STRING;
1101*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < KTAB_STRLEN; i++)
1102*7c478bd9Sstevel@tonic-gate 			keystringtab[strtabindex][i] = key->kio_string[i];
1103*7c478bd9Sstevel@tonic-gate 		keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
1104*7c478bd9Sstevel@tonic-gate 	}
1105*7c478bd9Sstevel@tonic-gate 	entry = key->kio_entry;
1106*7c478bd9Sstevel@tonic-gate 	/*
1107*7c478bd9Sstevel@tonic-gate 	 * There's nothing we need do with OLD_ISOCHAR.
1108*7c478bd9Sstevel@tonic-gate 	 */
1109*7c478bd9Sstevel@tonic-gate 	if (entry != OLD_ISOCHAR) {
1110*7c478bd9Sstevel@tonic-gate 		if (entry & 0x80) {
1111*7c478bd9Sstevel@tonic-gate 			if (entry >= OLD_FA_UMLAUT && entry <= OLD_FA_GRAVE)
1112*7c478bd9Sstevel@tonic-gate 				entry = FA_CLASS + (entry & 0x0F) - 9;
1113*7c478bd9Sstevel@tonic-gate 			else
1114*7c478bd9Sstevel@tonic-gate 				entry =
1115*7c478bd9Sstevel@tonic-gate 				    special_old_to_new[entry >> 4 & 0x07]
1116*7c478bd9Sstevel@tonic-gate 				    + (entry & 0x0F);
1117*7c478bd9Sstevel@tonic-gate 		}
1118*7c478bd9Sstevel@tonic-gate 	}
1119*7c478bd9Sstevel@tonic-gate 	km->keymap[key->kio_station] = entry;
1120*7c478bd9Sstevel@tonic-gate 	return (0);
1121*7c478bd9Sstevel@tonic-gate }
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate /*
1124*7c478bd9Sstevel@tonic-gate  * Map new special codes to old ones.
1125*7c478bd9Sstevel@tonic-gate  * Indexed by (new special code) >> 8; add (new special code) & 0xFF.
1126*7c478bd9Sstevel@tonic-gate  */
1127*7c478bd9Sstevel@tonic-gate static uchar_t	special_new_to_old[] = {
1128*7c478bd9Sstevel@tonic-gate 	0,			/* normal */
1129*7c478bd9Sstevel@tonic-gate 	OLD_SHIFTKEYS,		/* SHIFTKEYS */
1130*7c478bd9Sstevel@tonic-gate 	OLD_BUCKYBITS,		/* BUCKYBITS */
1131*7c478bd9Sstevel@tonic-gate 	OLD_FUNNY,		/* FUNNY */
1132*7c478bd9Sstevel@tonic-gate 	OLD_FA_UMLAUT,		/* FA_CLASS */
1133*7c478bd9Sstevel@tonic-gate 	OLD_STRING,		/* STRING */
1134*7c478bd9Sstevel@tonic-gate 	OLD_LEFTFUNC,		/* FUNCKEYS */
1135*7c478bd9Sstevel@tonic-gate };
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate /*
1138*7c478bd9Sstevel@tonic-gate  * Get individual keystation translation as old-style entry.
1139*7c478bd9Sstevel@tonic-gate  */
1140*7c478bd9Sstevel@tonic-gate static int
1141*7c478bd9Sstevel@tonic-gate kbdgetkey(register struct kbddata *kbdd, struct	kiockey *key)
1142*7c478bd9Sstevel@tonic-gate {
1143*7c478bd9Sstevel@tonic-gate 	int	strtabindex, i;
1144*7c478bd9Sstevel@tonic-gate 	struct	keymap *km;
1145*7c478bd9Sstevel@tonic-gate 	register ushort_t entry;
1146*7c478bd9Sstevel@tonic-gate 
1147*7c478bd9Sstevel@tonic-gate 	if (key->kio_station >= KEYMAP_SIZE)
1148*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1149*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_state.k_curkeyboard == NULL)
1150*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1151*7c478bd9Sstevel@tonic-gate 	if (key->kio_tablemask == KIOCABORT1) {
1152*7c478bd9Sstevel@tonic-gate 		key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort1;
1153*7c478bd9Sstevel@tonic-gate 		return (0);
1154*7c478bd9Sstevel@tonic-gate 	}
1155*7c478bd9Sstevel@tonic-gate 	if (key->kio_tablemask == KIOCABORT2) {
1156*7c478bd9Sstevel@tonic-gate 		key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort2;
1157*7c478bd9Sstevel@tonic-gate 		return (0);
1158*7c478bd9Sstevel@tonic-gate 	}
1159*7c478bd9Sstevel@tonic-gate 	if ((km = settable(kbdd, (uint_t)key->kio_tablemask)) == NULL)
1160*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1161*7c478bd9Sstevel@tonic-gate 	entry = km->keymap[key->kio_station];
1162*7c478bd9Sstevel@tonic-gate 	if (entry & 0xFF00)
1163*7c478bd9Sstevel@tonic-gate 		key->kio_entry =
1164*7c478bd9Sstevel@tonic-gate 		    special_new_to_old[(ushort_t)(entry & 0xFF00) >> 8]
1165*7c478bd9Sstevel@tonic-gate 		    + (entry & 0x00FF);
1166*7c478bd9Sstevel@tonic-gate 	else {
1167*7c478bd9Sstevel@tonic-gate 		if (entry & 0x80)
1168*7c478bd9Sstevel@tonic-gate 			key->kio_entry = (ushort_t)OLD_ISOCHAR;	/* you lose */
1169*7c478bd9Sstevel@tonic-gate 		else
1170*7c478bd9Sstevel@tonic-gate 			key->kio_entry = (ushort_t)entry;
1171*7c478bd9Sstevel@tonic-gate 	}
1172*7c478bd9Sstevel@tonic-gate 	if (entry >= STRING && entry <= (uchar_t)(STRING + 15)) {
1173*7c478bd9Sstevel@tonic-gate 		strtabindex = entry - STRING;
1174*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < KTAB_STRLEN; i++)
1175*7c478bd9Sstevel@tonic-gate 			key->kio_string[i] = keystringtab[strtabindex][i];
1176*7c478bd9Sstevel@tonic-gate 	}
1177*7c478bd9Sstevel@tonic-gate 	return (0);
1178*7c478bd9Sstevel@tonic-gate }
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate /*
1181*7c478bd9Sstevel@tonic-gate  * Set individual keystation translation from new-style entry.
1182*7c478bd9Sstevel@tonic-gate  * TODO: Have each keyboard own own translation tables.
1183*7c478bd9Sstevel@tonic-gate  */
1184*7c478bd9Sstevel@tonic-gate static int
1185*7c478bd9Sstevel@tonic-gate kbdskey(register struct kbddata *kbdd, struct kiockeymap *key, cred_t *cr)
1186*7c478bd9Sstevel@tonic-gate {
1187*7c478bd9Sstevel@tonic-gate 	int	strtabindex, i;
1188*7c478bd9Sstevel@tonic-gate 	struct	keymap *km;
1189*7c478bd9Sstevel@tonic-gate 
1190*7c478bd9Sstevel@tonic-gate 	if (key->kio_station >= KEYMAP_SIZE)
1191*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1192*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_state.k_curkeyboard == NULL)
1193*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1194*7c478bd9Sstevel@tonic-gate 	if (key->kio_tablemask == KIOCABORT1) {
1195*7c478bd9Sstevel@tonic-gate 		if (secpolicy_console(cr) != 0)
1196*7c478bd9Sstevel@tonic-gate 			return (EPERM);
1197*7c478bd9Sstevel@tonic-gate 		kbdd->kbdd_state.k_curkeyboard->k_abort1 = key->kio_station;
1198*7c478bd9Sstevel@tonic-gate 		return (0);
1199*7c478bd9Sstevel@tonic-gate 	}
1200*7c478bd9Sstevel@tonic-gate 	if (key->kio_tablemask == KIOCABORT2) {
1201*7c478bd9Sstevel@tonic-gate 		if (secpolicy_console(cr) != 0)
1202*7c478bd9Sstevel@tonic-gate 			return (EPERM);
1203*7c478bd9Sstevel@tonic-gate 		kbdd->kbdd_state.k_curkeyboard->k_abort2 = key->kio_station;
1204*7c478bd9Sstevel@tonic-gate 		return (0);
1205*7c478bd9Sstevel@tonic-gate 	}
1206*7c478bd9Sstevel@tonic-gate 	if ((km = settable(kbdd, (uint_t)key->kio_tablemask)) == NULL)
1207*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1208*7c478bd9Sstevel@tonic-gate 	if (key->kio_entry >= STRING &&
1209*7c478bd9Sstevel@tonic-gate 	    key->kio_entry <= (ushort_t)(STRING + 15)) {
1210*7c478bd9Sstevel@tonic-gate 		strtabindex = key->kio_entry-STRING;
1211*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < KTAB_STRLEN; i++)
1212*7c478bd9Sstevel@tonic-gate 			keystringtab[strtabindex][i] = key->kio_string[i];
1213*7c478bd9Sstevel@tonic-gate 		keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
1214*7c478bd9Sstevel@tonic-gate 	}
1215*7c478bd9Sstevel@tonic-gate 	km->keymap[key->kio_station] = key->kio_entry;
1216*7c478bd9Sstevel@tonic-gate 	return (0);
1217*7c478bd9Sstevel@tonic-gate }
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate /*
1220*7c478bd9Sstevel@tonic-gate  * Get individual keystation translation as new-style entry.
1221*7c478bd9Sstevel@tonic-gate  */
1222*7c478bd9Sstevel@tonic-gate static int
1223*7c478bd9Sstevel@tonic-gate kbdgkey(register struct kbddata *kbdd, struct	kiockeymap *key)
1224*7c478bd9Sstevel@tonic-gate {
1225*7c478bd9Sstevel@tonic-gate 	int	strtabindex, i;
1226*7c478bd9Sstevel@tonic-gate 	struct	keymap *km;
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 	if (key->kio_station >= KEYMAP_SIZE)
1229*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1230*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_state.k_curkeyboard == NULL)
1231*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1232*7c478bd9Sstevel@tonic-gate 	if (key->kio_tablemask == KIOCABORT1) {
1233*7c478bd9Sstevel@tonic-gate 		key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort1;
1234*7c478bd9Sstevel@tonic-gate 		return (0);
1235*7c478bd9Sstevel@tonic-gate 	}
1236*7c478bd9Sstevel@tonic-gate 	if (key->kio_tablemask == KIOCABORT2) {
1237*7c478bd9Sstevel@tonic-gate 		key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort2;
1238*7c478bd9Sstevel@tonic-gate 		return (0);
1239*7c478bd9Sstevel@tonic-gate 	}
1240*7c478bd9Sstevel@tonic-gate 	if ((km = settable(kbdd, (uint_t)key->kio_tablemask)) == NULL)
1241*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1242*7c478bd9Sstevel@tonic-gate 	key->kio_entry = km->keymap[key->kio_station];
1243*7c478bd9Sstevel@tonic-gate 	if (key->kio_entry >= STRING &&
1244*7c478bd9Sstevel@tonic-gate 	    key->kio_entry <= (ushort_t)(STRING + 15)) {
1245*7c478bd9Sstevel@tonic-gate 		strtabindex = key->kio_entry-STRING;
1246*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < KTAB_STRLEN; i++)
1247*7c478bd9Sstevel@tonic-gate 			key->kio_string[i] = keystringtab[strtabindex][i];
1248*7c478bd9Sstevel@tonic-gate 	}
1249*7c478bd9Sstevel@tonic-gate 	return (0);
1250*7c478bd9Sstevel@tonic-gate }
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate static void
1253*7c478bd9Sstevel@tonic-gate kbdlayouttimeout(void *arg)
1254*7c478bd9Sstevel@tonic-gate {
1255*7c478bd9Sstevel@tonic-gate 	struct kbddata *kbdd = arg;
1256*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
1257*7c478bd9Sstevel@tonic-gate 
1258*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_layoutid = 0;
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate 	/*
1261*7c478bd9Sstevel@tonic-gate 	 * Timed out waiting for reply to "get keyboard layout" command.
1262*7c478bd9Sstevel@tonic-gate 	 * Return an ETIME error.
1263*7c478bd9Sstevel@tonic-gate 	 */
1264*7c478bd9Sstevel@tonic-gate 	if ((mp = kbdd->kbdd_replypending) != NULL) {
1265*7c478bd9Sstevel@tonic-gate 		kbdd->kbdd_replypending = NULL;
1266*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
1267*7c478bd9Sstevel@tonic-gate 		((struct iocblk *)mp->b_rptr)->ioc_error = ETIME;
1268*7c478bd9Sstevel@tonic-gate 		putnext(kbdd->kbdd_readq, mp);
1269*7c478bd9Sstevel@tonic-gate 	}
1270*7c478bd9Sstevel@tonic-gate }
1271*7c478bd9Sstevel@tonic-gate 
1272*7c478bd9Sstevel@tonic-gate /*
1273*7c478bd9Sstevel@tonic-gate  * Put procedure for input from driver end of stream (read queue).
1274*7c478bd9Sstevel@tonic-gate  */
1275*7c478bd9Sstevel@tonic-gate static void
1276*7c478bd9Sstevel@tonic-gate kbdrput(register queue_t *q, register mblk_t *mp)
1277*7c478bd9Sstevel@tonic-gate {
1278*7c478bd9Sstevel@tonic-gate 	struct kbddata *kbdd = (struct kbddata *)q->q_ptr;
1279*7c478bd9Sstevel@tonic-gate 	register mblk_t *bp;
1280*7c478bd9Sstevel@tonic-gate 	register uchar_t *readp;
1281*7c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 	if (kbdd == 0) {
1284*7c478bd9Sstevel@tonic-gate 		freemsg(mp);	/* nobody's listening */
1285*7c478bd9Sstevel@tonic-gate 		return;
1286*7c478bd9Sstevel@tonic-gate 	}
1287*7c478bd9Sstevel@tonic-gate 
1288*7c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:
1291*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
1292*7c478bd9Sstevel@tonic-gate 			flushq(WR(q), FLUSHDATA);
1293*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
1294*7c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
1295*7c478bd9Sstevel@tonic-gate 
1296*7c478bd9Sstevel@tonic-gate 	default:
1297*7c478bd9Sstevel@tonic-gate 		putnext(q, mp);
1298*7c478bd9Sstevel@tonic-gate 		return;
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate 	case M_BREAK:
1301*7c478bd9Sstevel@tonic-gate 		/*
1302*7c478bd9Sstevel@tonic-gate 		 * Will get M_BREAK only if this is not the system
1303*7c478bd9Sstevel@tonic-gate 		 * keyboard, otherwise serial port will eat break
1304*7c478bd9Sstevel@tonic-gate 		 * and call kmdb/OBP, without passing anything up.
1305*7c478bd9Sstevel@tonic-gate 		 */
1306*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1307*7c478bd9Sstevel@tonic-gate 		return;
1308*7c478bd9Sstevel@tonic-gate 
1309*7c478bd9Sstevel@tonic-gate 	case M_IOCACK:
1310*7c478bd9Sstevel@tonic-gate 	case M_IOCNAK:
1311*7c478bd9Sstevel@tonic-gate 		/*
1312*7c478bd9Sstevel@tonic-gate 		 * If we are doing an "ioctl" ourselves, check if this
1313*7c478bd9Sstevel@tonic-gate 		 * is the reply to that code.  If so, wake up the
1314*7c478bd9Sstevel@tonic-gate 		 * "open" routine, and toss the reply, otherwise just
1315*7c478bd9Sstevel@tonic-gate 		 * pass it up.
1316*7c478bd9Sstevel@tonic-gate 		 */
1317*7c478bd9Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
1318*7c478bd9Sstevel@tonic-gate 		if (!(kbdd->kbdd_flags & KBD_IOCWAIT) ||
1319*7c478bd9Sstevel@tonic-gate 		    iocp->ioc_id != kbdd->kbdd_iocid) {
1320*7c478bd9Sstevel@tonic-gate 			/*
1321*7c478bd9Sstevel@tonic-gate 			 * This isn't the reply we're looking for.  Move along.
1322*7c478bd9Sstevel@tonic-gate 			 */
1323*7c478bd9Sstevel@tonic-gate 			if (kbdd->kbdd_flags & KBD_OPEN)
1324*7c478bd9Sstevel@tonic-gate 				putnext(q, mp);
1325*7c478bd9Sstevel@tonic-gate 			else
1326*7c478bd9Sstevel@tonic-gate 				freemsg(mp);	/* not ready to listen */
1327*7c478bd9Sstevel@tonic-gate 		} else {
1328*7c478bd9Sstevel@tonic-gate 			kbdd->kbdd_flags &= ~KBD_IOCWAIT;
1329*7c478bd9Sstevel@tonic-gate 			kbdd->kbdd_iocerror = iocp->ioc_error;
1330*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1331*7c478bd9Sstevel@tonic-gate 		}
1332*7c478bd9Sstevel@tonic-gate 		return;
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 	case M_DATA:
1335*7c478bd9Sstevel@tonic-gate 		if (!(kbdd->kbdd_flags & KBD_OPEN)) {
1336*7c478bd9Sstevel@tonic-gate 			freemsg(mp);	/* not read to listen */
1337*7c478bd9Sstevel@tonic-gate 			return;
1338*7c478bd9Sstevel@tonic-gate 		}
1339*7c478bd9Sstevel@tonic-gate 		break;
1340*7c478bd9Sstevel@tonic-gate 	}
1341*7c478bd9Sstevel@tonic-gate 
1342*7c478bd9Sstevel@tonic-gate 	/*
1343*7c478bd9Sstevel@tonic-gate 	 * A data message, consisting of bytes from the keyboard.
1344*7c478bd9Sstevel@tonic-gate 	 * Ram them through our state machine.
1345*7c478bd9Sstevel@tonic-gate 	 */
1346*7c478bd9Sstevel@tonic-gate 	bp = mp;
1347*7c478bd9Sstevel@tonic-gate 
1348*7c478bd9Sstevel@tonic-gate 	do {
1349*7c478bd9Sstevel@tonic-gate 		readp = bp->b_rptr;
1350*7c478bd9Sstevel@tonic-gate 		while (readp < bp->b_wptr)
1351*7c478bd9Sstevel@tonic-gate 			kbdinput(kbdd, *readp++);
1352*7c478bd9Sstevel@tonic-gate 		bp->b_rptr = readp;
1353*7c478bd9Sstevel@tonic-gate 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate 	freemsg(mp);
1356*7c478bd9Sstevel@tonic-gate }
1357*7c478bd9Sstevel@tonic-gate 
1358*7c478bd9Sstevel@tonic-gate /*
1359*7c478bd9Sstevel@tonic-gate  * A keypress was received. Process it through the state machine
1360*7c478bd9Sstevel@tonic-gate  * to check for aborts.
1361*7c478bd9Sstevel@tonic-gate  */
1362*7c478bd9Sstevel@tonic-gate static void
1363*7c478bd9Sstevel@tonic-gate kbdinput(register struct kbddata *kbdd, register unsigned key)
1364*7c478bd9Sstevel@tonic-gate {
1365*7c478bd9Sstevel@tonic-gate 	register struct keyboardstate *k;
1366*7c478bd9Sstevel@tonic-gate 	register mblk_t *mp;
1367*7c478bd9Sstevel@tonic-gate 
1368*7c478bd9Sstevel@tonic-gate 	k = &kbdd->kbdd_state;
1369*7c478bd9Sstevel@tonic-gate #ifdef	KBD_DEBUG
1370*7c478bd9Sstevel@tonic-gate 	if (kbd_input_debug)
1371*7c478bd9Sstevel@tonic-gate 		printf("kbdinput key %x\n", key);
1372*7c478bd9Sstevel@tonic-gate #endif
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate 	switch (k->k_idstate) {
1375*7c478bd9Sstevel@tonic-gate 
1376*7c478bd9Sstevel@tonic-gate 	case KID_NONE:
1377*7c478bd9Sstevel@tonic-gate 		if (key == RESETKEY) {
1378*7c478bd9Sstevel@tonic-gate 			k->k_idstate = KID_GOT_PREFACE;
1379*7c478bd9Sstevel@tonic-gate 		} else  {
1380*7c478bd9Sstevel@tonic-gate 			kbdreset(kbdd, HARD_RESET);
1381*7c478bd9Sstevel@tonic-gate 			/* allows hot plug of kbd after booting without kbd */
1382*7c478bd9Sstevel@tonic-gate 		}
1383*7c478bd9Sstevel@tonic-gate 		return;
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate 	case KID_GOT_PREFACE:
1386*7c478bd9Sstevel@tonic-gate 		kbdid(kbdd, (int)key);
1387*7c478bd9Sstevel@tonic-gate 
1388*7c478bd9Sstevel@tonic-gate 		/*
1389*7c478bd9Sstevel@tonic-gate 		 * We just did a reset command to a Type 3 or Type 4
1390*7c478bd9Sstevel@tonic-gate 		 * keyboard which sets the click back to the default
1391*7c478bd9Sstevel@tonic-gate 		 * (which is currently ON!).  We use the kbdclick
1392*7c478bd9Sstevel@tonic-gate 		 * variable to see if the keyboard should be turned on
1393*7c478bd9Sstevel@tonic-gate 		 * or off.  If it has not been set, then we use the
1394*7c478bd9Sstevel@tonic-gate 		 * keyboard-click? property.
1395*7c478bd9Sstevel@tonic-gate 		 */
1396*7c478bd9Sstevel@tonic-gate 		switch (kbdclick) {
1397*7c478bd9Sstevel@tonic-gate 		case 0:
1398*7c478bd9Sstevel@tonic-gate 			kbdcmd(kbdd->kbdd_writeq, KBD_CMD_NOCLICK);
1399*7c478bd9Sstevel@tonic-gate 			break;
1400*7c478bd9Sstevel@tonic-gate 		case 1:
1401*7c478bd9Sstevel@tonic-gate 			kbdcmd(kbdd->kbdd_writeq, KBD_CMD_CLICK);
1402*7c478bd9Sstevel@tonic-gate 			break;
1403*7c478bd9Sstevel@tonic-gate 		case -1:
1404*7c478bd9Sstevel@tonic-gate 		default:
1405*7c478bd9Sstevel@tonic-gate 			{
1406*7c478bd9Sstevel@tonic-gate 				char wrkbuf[8];
1407*7c478bd9Sstevel@tonic-gate 				int len;
1408*7c478bd9Sstevel@tonic-gate 
1409*7c478bd9Sstevel@tonic-gate 				kbdcmd(kbdd->kbdd_writeq, KBD_CMD_NOCLICK);
1410*7c478bd9Sstevel@tonic-gate 
1411*7c478bd9Sstevel@tonic-gate 				bzero(wrkbuf, 8);
1412*7c478bd9Sstevel@tonic-gate 				len = 7;
1413*7c478bd9Sstevel@tonic-gate 				if (ddi_getlongprop_buf(DDI_DEV_T_ANY,
1414*7c478bd9Sstevel@tonic-gate 				    ddi_root_node(), 0, "keyboard-click?",
1415*7c478bd9Sstevel@tonic-gate 				    (caddr_t)wrkbuf, &len) ==
1416*7c478bd9Sstevel@tonic-gate 				    DDI_PROP_SUCCESS &&
1417*7c478bd9Sstevel@tonic-gate 				    len > 0 && len < 8) {
1418*7c478bd9Sstevel@tonic-gate 					if (strcmp(wrkbuf, "true") == 0) {
1419*7c478bd9Sstevel@tonic-gate 						kbdcmd(kbdd->kbdd_writeq,
1420*7c478bd9Sstevel@tonic-gate 							KBD_CMD_CLICK);
1421*7c478bd9Sstevel@tonic-gate 					}
1422*7c478bd9Sstevel@tonic-gate 				}
1423*7c478bd9Sstevel@tonic-gate 			}
1424*7c478bd9Sstevel@tonic-gate 			break;
1425*7c478bd9Sstevel@tonic-gate 		}
1426*7c478bd9Sstevel@tonic-gate 		/*
1427*7c478bd9Sstevel@tonic-gate 		 * A keyboard reset clears the LEDs.
1428*7c478bd9Sstevel@tonic-gate 		 * Restore the LEDs from the last value we set
1429*7c478bd9Sstevel@tonic-gate 		 * them to.
1430*7c478bd9Sstevel@tonic-gate 		 */
1431*7c478bd9Sstevel@tonic-gate 		kbdsetled(kbdd);
1432*7c478bd9Sstevel@tonic-gate 		return;
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate 	case KID_OK:
1435*7c478bd9Sstevel@tonic-gate 		switch (key) {
1436*7c478bd9Sstevel@tonic-gate 
1437*7c478bd9Sstevel@tonic-gate #if	defined(KBD_PRESSED_PREFIX)
1438*7c478bd9Sstevel@tonic-gate 		case KBD_PRESSED_PREFIX:
1439*7c478bd9Sstevel@tonic-gate 			k->k_idstate = KID_GOT_PRESSED;
1440*7c478bd9Sstevel@tonic-gate 			return;
1441*7c478bd9Sstevel@tonic-gate #endif
1442*7c478bd9Sstevel@tonic-gate 
1443*7c478bd9Sstevel@tonic-gate #if	defined(KBD_RELEASED_PREFIX)
1444*7c478bd9Sstevel@tonic-gate 		case KBD_RELEASED_PREFIX:
1445*7c478bd9Sstevel@tonic-gate 			k->k_idstate = KID_GOT_RELEASED;
1446*7c478bd9Sstevel@tonic-gate 			return;
1447*7c478bd9Sstevel@tonic-gate #endif
1448*7c478bd9Sstevel@tonic-gate 
1449*7c478bd9Sstevel@tonic-gate 		case 0:
1450*7c478bd9Sstevel@tonic-gate 			kbdreset(kbdd, HARD_RESET);
1451*7c478bd9Sstevel@tonic-gate 			return;
1452*7c478bd9Sstevel@tonic-gate 
1453*7c478bd9Sstevel@tonic-gate 		/*
1454*7c478bd9Sstevel@tonic-gate 		 * we want to check for ID only if we are in
1455*7c478bd9Sstevel@tonic-gate 		 * translatable mode.
1456*7c478bd9Sstevel@tonic-gate 		 */
1457*7c478bd9Sstevel@tonic-gate 		case RESETKEY:
1458*7c478bd9Sstevel@tonic-gate 			kbdreset(kbdd, NO_HARD_RESET);
1459*7c478bd9Sstevel@tonic-gate 			if (k->k_idstate == KID_NONE) {
1460*7c478bd9Sstevel@tonic-gate 				k->k_idstate = KID_GOT_PREFACE;
1461*7c478bd9Sstevel@tonic-gate 			}
1462*7c478bd9Sstevel@tonic-gate 			return;
1463*7c478bd9Sstevel@tonic-gate 
1464*7c478bd9Sstevel@tonic-gate 		case LAYOUTKEY:
1465*7c478bd9Sstevel@tonic-gate 			k->k_idstate = KID_GOT_LAYOUT;
1466*7c478bd9Sstevel@tonic-gate 			return;
1467*7c478bd9Sstevel@tonic-gate 		}
1468*7c478bd9Sstevel@tonic-gate 		break;
1469*7c478bd9Sstevel@tonic-gate 
1470*7c478bd9Sstevel@tonic-gate #if	defined(KBD_PRESSED_PREFIX)
1471*7c478bd9Sstevel@tonic-gate 	case KID_GOT_PRESSED:
1472*7c478bd9Sstevel@tonic-gate 		key = BUILDKEY(key, PRESSED);
1473*7c478bd9Sstevel@tonic-gate 		k->k_idstate = KID_OK;
1474*7c478bd9Sstevel@tonic-gate 		break;
1475*7c478bd9Sstevel@tonic-gate #endif
1476*7c478bd9Sstevel@tonic-gate #if	defined(KBD_RELEASED_PREFIX)
1477*7c478bd9Sstevel@tonic-gate 	case KID_GOT_RELEASED:
1478*7c478bd9Sstevel@tonic-gate 		key = BUILDKEY(key, RELEASED);
1479*7c478bd9Sstevel@tonic-gate 		k->k_idstate = KID_OK;
1480*7c478bd9Sstevel@tonic-gate 		break;
1481*7c478bd9Sstevel@tonic-gate #endif
1482*7c478bd9Sstevel@tonic-gate 
1483*7c478bd9Sstevel@tonic-gate 	case KID_GOT_LAYOUT:
1484*7c478bd9Sstevel@tonic-gate 		if (kbdd->kbdd_layoutid)
1485*7c478bd9Sstevel@tonic-gate 			(void) quntimeout(kbdd->kbdd_readq,
1486*7c478bd9Sstevel@tonic-gate 			    kbdd->kbdd_layoutid);
1487*7c478bd9Sstevel@tonic-gate 		if ((mp = kbdd->kbdd_replypending) != NULL) {
1488*7c478bd9Sstevel@tonic-gate 			kbdd->kbdd_replypending = NULL;
1489*7c478bd9Sstevel@tonic-gate 			*(int *)mp->b_cont->b_wptr = key;
1490*7c478bd9Sstevel@tonic-gate 			mp->b_cont->b_wptr += sizeof (int);
1491*7c478bd9Sstevel@tonic-gate 			putnext(kbdd->kbdd_readq, mp);
1492*7c478bd9Sstevel@tonic-gate 		}
1493*7c478bd9Sstevel@tonic-gate 		k->k_idstate = KID_OK;
1494*7c478bd9Sstevel@tonic-gate 		return;
1495*7c478bd9Sstevel@tonic-gate 	}
1496*7c478bd9Sstevel@tonic-gate 
1497*7c478bd9Sstevel@tonic-gate 	switch (k->k_state) {
1498*7c478bd9Sstevel@tonic-gate 
1499*7c478bd9Sstevel@tonic-gate #if defined(__sparc)
1500*7c478bd9Sstevel@tonic-gate 	normalstate:
1501*7c478bd9Sstevel@tonic-gate 		k->k_state = NORMAL;
1502*7c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
1503*7c478bd9Sstevel@tonic-gate #endif
1504*7c478bd9Sstevel@tonic-gate 	case NORMAL:
1505*7c478bd9Sstevel@tonic-gate #if defined(__sparc)
1506*7c478bd9Sstevel@tonic-gate 		if (k->k_curkeyboard) {
1507*7c478bd9Sstevel@tonic-gate 			if (key == k->k_curkeyboard->k_abort1) {
1508*7c478bd9Sstevel@tonic-gate 				k->k_state = ABORT1;
1509*7c478bd9Sstevel@tonic-gate 				break;
1510*7c478bd9Sstevel@tonic-gate 			}
1511*7c478bd9Sstevel@tonic-gate 		}
1512*7c478bd9Sstevel@tonic-gate #endif
1513*7c478bd9Sstevel@tonic-gate 		kbduse(kbdd, key);
1514*7c478bd9Sstevel@tonic-gate 		break;
1515*7c478bd9Sstevel@tonic-gate 
1516*7c478bd9Sstevel@tonic-gate #if defined(__sparc)
1517*7c478bd9Sstevel@tonic-gate 	case ABORT1:
1518*7c478bd9Sstevel@tonic-gate 		if (k->k_curkeyboard) {
1519*7c478bd9Sstevel@tonic-gate 			/*
1520*7c478bd9Sstevel@tonic-gate 			 * Only recognize this as an abort sequence if
1521*7c478bd9Sstevel@tonic-gate 			 * the "hardware" console is set to be this device.
1522*7c478bd9Sstevel@tonic-gate 			 */
1523*7c478bd9Sstevel@tonic-gate 			if (key == k->k_curkeyboard->k_abort2 &&
1524*7c478bd9Sstevel@tonic-gate 			    rconsvp == wsconsvp) {
1525*7c478bd9Sstevel@tonic-gate 				DELAY(100000);
1526*7c478bd9Sstevel@tonic-gate 				abort_sequence_enter((char *)NULL);
1527*7c478bd9Sstevel@tonic-gate 				k->k_state = NORMAL;
1528*7c478bd9Sstevel@tonic-gate 				kbduse(kbdd, IDLEKEY);	/* fake */
1529*7c478bd9Sstevel@tonic-gate 				return;
1530*7c478bd9Sstevel@tonic-gate 			} else {
1531*7c478bd9Sstevel@tonic-gate 				kbduse(kbdd, k->k_curkeyboard->k_abort1);
1532*7c478bd9Sstevel@tonic-gate 				goto normalstate;
1533*7c478bd9Sstevel@tonic-gate 			}
1534*7c478bd9Sstevel@tonic-gate 		}
1535*7c478bd9Sstevel@tonic-gate 		break;
1536*7c478bd9Sstevel@tonic-gate #endif
1537*7c478bd9Sstevel@tonic-gate 
1538*7c478bd9Sstevel@tonic-gate 	case COMPOSE1:
1539*7c478bd9Sstevel@tonic-gate 	case COMPOSE2:
1540*7c478bd9Sstevel@tonic-gate 	case FLTACCENT:
1541*7c478bd9Sstevel@tonic-gate 		if (key != IDLEKEY)
1542*7c478bd9Sstevel@tonic-gate 			kbduse(kbdd, key);
1543*7c478bd9Sstevel@tonic-gate 		break;
1544*7c478bd9Sstevel@tonic-gate 	}
1545*7c478bd9Sstevel@tonic-gate }
1546*7c478bd9Sstevel@tonic-gate 
1547*7c478bd9Sstevel@tonic-gate static void
1548*7c478bd9Sstevel@tonic-gate kbdid(register struct kbddata *kbdd, int id)
1549*7c478bd9Sstevel@tonic-gate {
1550*7c478bd9Sstevel@tonic-gate 	register struct keyboardstate *k;
1551*7c478bd9Sstevel@tonic-gate 	int	i;
1552*7c478bd9Sstevel@tonic-gate 
1553*7c478bd9Sstevel@tonic-gate 	k = &kbdd->kbdd_state;
1554*7c478bd9Sstevel@tonic-gate 
1555*7c478bd9Sstevel@tonic-gate 	k->k_idstate = KID_OK;
1556*7c478bd9Sstevel@tonic-gate 	k->k_shiftmask = 0;
1557*7c478bd9Sstevel@tonic-gate 	k->k_buckybits = 0;
1558*7c478bd9Sstevel@tonic-gate 
1559*7c478bd9Sstevel@tonic-gate 	/*
1560*7c478bd9Sstevel@tonic-gate 	 * Reset k_rptkey to IDLEKEY. We need to cancel
1561*7c478bd9Sstevel@tonic-gate 	 * the autorepeat feature, if any.
1562*7c478bd9Sstevel@tonic-gate 	 */
1563*7c478bd9Sstevel@tonic-gate 	if (k->k_rptkey != IDLEKEY) {
1564*7c478bd9Sstevel@tonic-gate 		if (kbdd->kbdd_rptid)
1565*7c478bd9Sstevel@tonic-gate 			(void) quntimeout(kbdd->kbdd_readq, kbdd->kbdd_rptid);
1566*7c478bd9Sstevel@tonic-gate 		kbdd->kbdd_rptid = 0;
1567*7c478bd9Sstevel@tonic-gate 		k->k_rptkey = IDLEKEY;
1568*7c478bd9Sstevel@tonic-gate 	}
1569*7c478bd9Sstevel@tonic-gate 
1570*7c478bd9Sstevel@tonic-gate 	k->k_curkeyboard = NULL;
1571*7c478bd9Sstevel@tonic-gate 	for (i = 0; keytables[i].table; i++) {
1572*7c478bd9Sstevel@tonic-gate 		if (keytables[i].id == id) {
1573*7c478bd9Sstevel@tonic-gate 			k->k_id = id;
1574*7c478bd9Sstevel@tonic-gate 			k->k_curkeyboard = keytables[i].table;
1575*7c478bd9Sstevel@tonic-gate 			break;
1576*7c478bd9Sstevel@tonic-gate 		}
1577*7c478bd9Sstevel@tonic-gate 	}
1578*7c478bd9Sstevel@tonic-gate 	if (!k->k_curkeyboard) {
1579*7c478bd9Sstevel@tonic-gate 		k->k_id = keytables[0].id;
1580*7c478bd9Sstevel@tonic-gate 		k->k_curkeyboard = keytables[0].table;
1581*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "kbd: Unknown keyboard type, "
1582*7c478bd9Sstevel@tonic-gate 			"Type %d assumed", k->k_id);
1583*7c478bd9Sstevel@tonic-gate 	}
1584*7c478bd9Sstevel@tonic-gate }
1585*7c478bd9Sstevel@tonic-gate 
1586*7c478bd9Sstevel@tonic-gate /*
1587*7c478bd9Sstevel@tonic-gate  * This routine determines which table we should look in to decode
1588*7c478bd9Sstevel@tonic-gate  * the current keycode.
1589*7c478bd9Sstevel@tonic-gate  */
1590*7c478bd9Sstevel@tonic-gate static struct keymap *
1591*7c478bd9Sstevel@tonic-gate settable(register struct kbddata *kbdd, register uint_t mask)
1592*7c478bd9Sstevel@tonic-gate {
1593*7c478bd9Sstevel@tonic-gate 	register struct keyboard *kp;
1594*7c478bd9Sstevel@tonic-gate 
1595*7c478bd9Sstevel@tonic-gate 	kp = kbdd->kbdd_state.k_curkeyboard;
1596*7c478bd9Sstevel@tonic-gate 	if (kp == NULL)
1597*7c478bd9Sstevel@tonic-gate 		return (NULL);
1598*7c478bd9Sstevel@tonic-gate 	if (mask & UPMASK)
1599*7c478bd9Sstevel@tonic-gate 		return (kp->k_up);
1600*7c478bd9Sstevel@tonic-gate 	if (mask & NUMLOCKMASK)
1601*7c478bd9Sstevel@tonic-gate 		return (kp->k_numlock);
1602*7c478bd9Sstevel@tonic-gate 	if (mask & CTRLMASK)
1603*7c478bd9Sstevel@tonic-gate 		return (kp->k_control);
1604*7c478bd9Sstevel@tonic-gate 	if (mask & ALTGRAPHMASK)
1605*7c478bd9Sstevel@tonic-gate 		return (kp->k_altgraph);
1606*7c478bd9Sstevel@tonic-gate 	if (mask & SHIFTMASK)
1607*7c478bd9Sstevel@tonic-gate 		return (kp->k_shifted);
1608*7c478bd9Sstevel@tonic-gate 	if (mask & CAPSMASK)
1609*7c478bd9Sstevel@tonic-gate 		return (kp->k_caps);
1610*7c478bd9Sstevel@tonic-gate 	return (kp->k_normal);
1611*7c478bd9Sstevel@tonic-gate }
1612*7c478bd9Sstevel@tonic-gate 
1613*7c478bd9Sstevel@tonic-gate static void
1614*7c478bd9Sstevel@tonic-gate kbdrpt(void *arg)
1615*7c478bd9Sstevel@tonic-gate {
1616*7c478bd9Sstevel@tonic-gate 	struct kbddata *kbdd = arg;
1617*7c478bd9Sstevel@tonic-gate 	struct keyboardstate *k;
1618*7c478bd9Sstevel@tonic-gate 
1619*7c478bd9Sstevel@tonic-gate 	k = &kbdd->kbdd_state;
1620*7c478bd9Sstevel@tonic-gate #ifdef	KBD_DEBUG
1621*7c478bd9Sstevel@tonic-gate 	if (kbd_rpt_debug)
1622*7c478bd9Sstevel@tonic-gate 		printf("kbdrpt key %x\n", k->k_rptkey);
1623*7c478bd9Sstevel@tonic-gate #endif
1624*7c478bd9Sstevel@tonic-gate 	kbdd->kbdd_rptid = 0;
1625*7c478bd9Sstevel@tonic-gate 
1626*7c478bd9Sstevel@tonic-gate 	kbdkeyreleased(kbdd, KEYOF(k->k_rptkey));
1627*7c478bd9Sstevel@tonic-gate 	kbduse(kbdd, k->k_rptkey);
1628*7c478bd9Sstevel@tonic-gate 	if (k->k_rptkey != IDLEKEY) {
1629*7c478bd9Sstevel@tonic-gate 		kbdd->kbdd_rptid = qtimeout(kbdd->kbdd_readq, kbdrpt,
1630*7c478bd9Sstevel@tonic-gate 		    kbdd, kbd_repeatrate);
1631*7c478bd9Sstevel@tonic-gate 	}
1632*7c478bd9Sstevel@tonic-gate }
1633*7c478bd9Sstevel@tonic-gate 
1634*7c478bd9Sstevel@tonic-gate static void
1635*7c478bd9Sstevel@tonic-gate kbdcancelrpt(register struct kbddata *kbdd)
1636*7c478bd9Sstevel@tonic-gate {
1637*7c478bd9Sstevel@tonic-gate 	register struct keyboardstate *k;
1638*7c478bd9Sstevel@tonic-gate 
1639*7c478bd9Sstevel@tonic-gate 	k = &kbdd->kbdd_state;
1640*7c478bd9Sstevel@tonic-gate 	if (k->k_rptkey != IDLEKEY) {
1641*7c478bd9Sstevel@tonic-gate 		if (kbdd->kbdd_rptid)
1642*7c478bd9Sstevel@tonic-gate 			(void) quntimeout(kbdd->kbdd_readq, kbdd->kbdd_rptid);
1643*7c478bd9Sstevel@tonic-gate 		kbdd->kbdd_rptid = 0;
1644*7c478bd9Sstevel@tonic-gate 		k->k_rptkey = IDLEKEY;
1645*7c478bd9Sstevel@tonic-gate 	}
1646*7c478bd9Sstevel@tonic-gate 	ASSERT(kbdd->kbdd_rptid == 0);
1647*7c478bd9Sstevel@tonic-gate }
1648*7c478bd9Sstevel@tonic-gate 
1649*7c478bd9Sstevel@tonic-gate static void
1650*7c478bd9Sstevel@tonic-gate kbdtranslate(struct kbddata *kbdd, unsigned keycode, queue_t *q)
1651*7c478bd9Sstevel@tonic-gate {
1652*7c478bd9Sstevel@tonic-gate 	register uchar_t key;
1653*7c478bd9Sstevel@tonic-gate 	register unsigned newstate;
1654*7c478bd9Sstevel@tonic-gate 	unsigned shiftmask;
1655*7c478bd9Sstevel@tonic-gate 	register ushort_t entry, entrytype;
1656*7c478bd9Sstevel@tonic-gate 	register char *cp, *bufp;
1657*7c478bd9Sstevel@tonic-gate 	register struct keyboardstate *k;
1658*7c478bd9Sstevel@tonic-gate 	ushort_t result_iso;
1659*7c478bd9Sstevel@tonic-gate 	struct keymap *km;
1660*7c478bd9Sstevel@tonic-gate 	Firm_event fe;
1661*7c478bd9Sstevel@tonic-gate 	int i, ret_val;
1662*7c478bd9Sstevel@tonic-gate 	char buf[14];
1663*7c478bd9Sstevel@tonic-gate 
1664*7c478bd9Sstevel@tonic-gate 	k = &kbdd->kbdd_state;
1665*7c478bd9Sstevel@tonic-gate 	newstate = STATEOF(keycode);
1666*7c478bd9Sstevel@tonic-gate 	key = KEYOF(keycode);
1667*7c478bd9Sstevel@tonic-gate 
1668*7c478bd9Sstevel@tonic-gate #ifdef	KBD_DEBUG
1669*7c478bd9Sstevel@tonic-gate 	if (kbd_input_debug) {
1670*7c478bd9Sstevel@tonic-gate 		printf("KBD TRANSLATE keycode=0x%x newstate=0x%x key=0x%x\n",
1671*7c478bd9Sstevel@tonic-gate 		    keycode, newstate, key);
1672*7c478bd9Sstevel@tonic-gate 	}
1673*7c478bd9Sstevel@tonic-gate #endif
1674*7c478bd9Sstevel@tonic-gate 
1675*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_translate == TR_UNTRANS_EVENT) {
1676*7c478bd9Sstevel@tonic-gate 		if (newstate == PRESSED) {
1677*7c478bd9Sstevel@tonic-gate 			bzero(&fe, sizeof (fe));
1678*7c478bd9Sstevel@tonic-gate 			fe.id = key;
1679*7c478bd9Sstevel@tonic-gate 			fe.value = 1;
1680*7c478bd9Sstevel@tonic-gate 			kbdqueuepress(kbdd, key, &fe);
1681*7c478bd9Sstevel@tonic-gate 		} else {
1682*7c478bd9Sstevel@tonic-gate 			kbdkeyreleased(kbdd, key);
1683*7c478bd9Sstevel@tonic-gate 		}
1684*7c478bd9Sstevel@tonic-gate 		return;
1685*7c478bd9Sstevel@tonic-gate 	}
1686*7c478bd9Sstevel@tonic-gate 
1687*7c478bd9Sstevel@tonic-gate 	shiftmask = k->k_shiftmask;
1688*7c478bd9Sstevel@tonic-gate 	if (newstate == RELEASED)
1689*7c478bd9Sstevel@tonic-gate 		shiftmask |= UPMASK;
1690*7c478bd9Sstevel@tonic-gate 
1691*7c478bd9Sstevel@tonic-gate 	km = settable(kbdd, shiftmask);
1692*7c478bd9Sstevel@tonic-gate 	if (km == NULL) {		/* gross error */
1693*7c478bd9Sstevel@tonic-gate 		kbdcancelrpt(kbdd);
1694*7c478bd9Sstevel@tonic-gate 		return;
1695*7c478bd9Sstevel@tonic-gate 	}
1696*7c478bd9Sstevel@tonic-gate 
1697*7c478bd9Sstevel@tonic-gate 	if (key >= KEYMAP_SIZE)
1698*7c478bd9Sstevel@tonic-gate 		return;
1699*7c478bd9Sstevel@tonic-gate 	entry = km->keymap[key];
1700*7c478bd9Sstevel@tonic-gate 
1701*7c478bd9Sstevel@tonic-gate 	if (entry == NONL) {
1702*7c478bd9Sstevel@tonic-gate 		/*
1703*7c478bd9Sstevel@tonic-gate 		 * NONL appears only in the Num Lock table, and indicates that
1704*7c478bd9Sstevel@tonic-gate 		 * this key is not affected by Num Lock.  This means we should
1705*7c478bd9Sstevel@tonic-gate 		 * ask for the table we would have gotten had Num Lock not been
1706*7c478bd9Sstevel@tonic-gate 		 * down, and translate using that table.
1707*7c478bd9Sstevel@tonic-gate 		 */
1708*7c478bd9Sstevel@tonic-gate 		km = settable(kbdd, shiftmask & ~NUMLOCKMASK);
1709*7c478bd9Sstevel@tonic-gate 		if (km == NULL) {		/* gross error */
1710*7c478bd9Sstevel@tonic-gate 			kbdcancelrpt(kbdd);
1711*7c478bd9Sstevel@tonic-gate 			return;
1712*7c478bd9Sstevel@tonic-gate 		}
1713*7c478bd9Sstevel@tonic-gate 		entry = km->keymap[key];
1714*7c478bd9Sstevel@tonic-gate 	}
1715*7c478bd9Sstevel@tonic-gate 	entrytype = (ushort_t)(entry & 0xFF00) >> 8;
1716*7c478bd9Sstevel@tonic-gate 
1717*7c478bd9Sstevel@tonic-gate 	if (entrytype == (SHIFTKEYS >> 8)) {
1718*7c478bd9Sstevel@tonic-gate 		/*
1719*7c478bd9Sstevel@tonic-gate 		 * Handle the state of toggle shifts specially.
1720*7c478bd9Sstevel@tonic-gate 		 * Ups should be ignored, and downs should be mapped to ups if
1721*7c478bd9Sstevel@tonic-gate 		 * that shift is currently on.
1722*7c478bd9Sstevel@tonic-gate 		 */
1723*7c478bd9Sstevel@tonic-gate 		if ((1 << (entry & 0x0F)) & k->k_curkeyboard->k_toggleshifts) {
1724*7c478bd9Sstevel@tonic-gate 			if ((1 << (entry & 0x0F)) & k->k_togglemask) {
1725*7c478bd9Sstevel@tonic-gate 				newstate = RELEASED;	/* toggling off */
1726*7c478bd9Sstevel@tonic-gate 			} else {
1727*7c478bd9Sstevel@tonic-gate 				newstate = PRESSED;	/* toggling on */
1728*7c478bd9Sstevel@tonic-gate 			}
1729*7c478bd9Sstevel@tonic-gate 		}
1730*7c478bd9Sstevel@tonic-gate 	} else {
1731*7c478bd9Sstevel@tonic-gate 		/*
1732*7c478bd9Sstevel@tonic-gate 		 * Handle Compose and floating accent key sequences
1733*7c478bd9Sstevel@tonic-gate 		 */
1734*7c478bd9Sstevel@tonic-gate 		if (k->k_state == COMPOSE1) {
1735*7c478bd9Sstevel@tonic-gate 			if (newstate == RELEASED)
1736*7c478bd9Sstevel@tonic-gate 				return;
1737*7c478bd9Sstevel@tonic-gate 			if (entry < ASCII_SET_SIZE) {
1738*7c478bd9Sstevel@tonic-gate 				if (kb_compose_map[entry] >= 0) {
1739*7c478bd9Sstevel@tonic-gate 					kbdd->compose_key = entry;
1740*7c478bd9Sstevel@tonic-gate 					k->k_state = COMPOSE2;
1741*7c478bd9Sstevel@tonic-gate 					return;
1742*7c478bd9Sstevel@tonic-gate 				}
1743*7c478bd9Sstevel@tonic-gate 			}
1744*7c478bd9Sstevel@tonic-gate 			k->k_state = NORMAL;
1745*7c478bd9Sstevel@tonic-gate 			kbdd->led_state &= ~LED_COMPOSE;
1746*7c478bd9Sstevel@tonic-gate 			kbdsetled(kbdd);
1747*7c478bd9Sstevel@tonic-gate 			return;
1748*7c478bd9Sstevel@tonic-gate 		} else if (k->k_state == COMPOSE2) {
1749*7c478bd9Sstevel@tonic-gate 			if (newstate == RELEASED)
1750*7c478bd9Sstevel@tonic-gate 				return;
1751*7c478bd9Sstevel@tonic-gate 			k->k_state = NORMAL;	/* next state is "normal" */
1752*7c478bd9Sstevel@tonic-gate 			kbdd->led_state &= ~LED_COMPOSE;
1753*7c478bd9Sstevel@tonic-gate 			kbdsetled(kbdd);
1754*7c478bd9Sstevel@tonic-gate 			if (entry < ASCII_SET_SIZE) {
1755*7c478bd9Sstevel@tonic-gate 				if (kb_compose_map[entry] >= 0) {
1756*7c478bd9Sstevel@tonic-gate 					if (kbdd->compose_key <= entry) {
1757*7c478bd9Sstevel@tonic-gate 						ret_val = kbd_do_compose(
1758*7c478bd9Sstevel@tonic-gate 							kbdd->compose_key,
1759*7c478bd9Sstevel@tonic-gate 							entry,
1760*7c478bd9Sstevel@tonic-gate 							&result_iso);
1761*7c478bd9Sstevel@tonic-gate 					} else {
1762*7c478bd9Sstevel@tonic-gate 						ret_val = kbd_do_compose(
1763*7c478bd9Sstevel@tonic-gate 							entry,
1764*7c478bd9Sstevel@tonic-gate 							kbdd->compose_key,
1765*7c478bd9Sstevel@tonic-gate 							&result_iso);
1766*7c478bd9Sstevel@tonic-gate 					}
1767*7c478bd9Sstevel@tonic-gate 					if (ret_val == 1) {
1768*7c478bd9Sstevel@tonic-gate 						if (kbdd->kbdd_translate ==
1769*7c478bd9Sstevel@tonic-gate 								TR_EVENT) {
1770*7c478bd9Sstevel@tonic-gate 							fe.id =
1771*7c478bd9Sstevel@tonic-gate 							(kbdd->kbdd_compat ?
1772*7c478bd9Sstevel@tonic-gate 							ISO_FIRST : EUC_FIRST)
1773*7c478bd9Sstevel@tonic-gate 							+ result_iso;
1774*7c478bd9Sstevel@tonic-gate 							fe.value = 1;
1775*7c478bd9Sstevel@tonic-gate 							kbdqueueevent(
1776*7c478bd9Sstevel@tonic-gate 								kbdd,
1777*7c478bd9Sstevel@tonic-gate 								&fe);
1778*7c478bd9Sstevel@tonic-gate 						} else if (
1779*7c478bd9Sstevel@tonic-gate 							kbdd->kbdd_translate ==
1780*7c478bd9Sstevel@tonic-gate 								TR_ASCII)
1781*7c478bd9Sstevel@tonic-gate 							kbdputcode(
1782*7c478bd9Sstevel@tonic-gate 								result_iso,
1783*7c478bd9Sstevel@tonic-gate 								q);
1784*7c478bd9Sstevel@tonic-gate 					}
1785*7c478bd9Sstevel@tonic-gate 				}
1786*7c478bd9Sstevel@tonic-gate 			}
1787*7c478bd9Sstevel@tonic-gate 			return;
1788*7c478bd9Sstevel@tonic-gate 		} else if (k->k_state == FLTACCENT) {
1789*7c478bd9Sstevel@tonic-gate 			if (newstate == RELEASED)
1790*7c478bd9Sstevel@tonic-gate 				return;
1791*7c478bd9Sstevel@tonic-gate 			k->k_state = NORMAL;	/* next state is "normal" */
1792*7c478bd9Sstevel@tonic-gate 			for (i = 0;
1793*7c478bd9Sstevel@tonic-gate 			    (kb_fltaccent_table[i].fa_entry
1794*7c478bd9Sstevel@tonic-gate 				!= kbdd->fltaccent_entry) ||
1795*7c478bd9Sstevel@tonic-gate 			    (kb_fltaccent_table[i].ascii != entry);
1796*7c478bd9Sstevel@tonic-gate 			    i++) {
1797*7c478bd9Sstevel@tonic-gate 				if (kb_fltaccent_table[i].fa_entry == 0)
1798*7c478bd9Sstevel@tonic-gate 					/* Invalid second key: ignore key */
1799*7c478bd9Sstevel@tonic-gate 					return;
1800*7c478bd9Sstevel@tonic-gate 			}
1801*7c478bd9Sstevel@tonic-gate 			if (kbdd->kbdd_translate == TR_EVENT) {
1802*7c478bd9Sstevel@tonic-gate 				fe.id = (kbdd->kbdd_compat ?
1803*7c478bd9Sstevel@tonic-gate 					ISO_FIRST : EUC_FIRST)
1804*7c478bd9Sstevel@tonic-gate 					+ kb_fltaccent_table[i].iso;
1805*7c478bd9Sstevel@tonic-gate 				fe.value = 1;
1806*7c478bd9Sstevel@tonic-gate 				kbdqueueevent(kbdd, &fe);
1807*7c478bd9Sstevel@tonic-gate 			} else if (kbdd->kbdd_translate == TR_ASCII)
1808*7c478bd9Sstevel@tonic-gate 				kbdputcode(kb_fltaccent_table[i].iso, q);
1809*7c478bd9Sstevel@tonic-gate 			return;
1810*7c478bd9Sstevel@tonic-gate 		}
1811*7c478bd9Sstevel@tonic-gate 	}
1812*7c478bd9Sstevel@tonic-gate 
1813*7c478bd9Sstevel@tonic-gate 	/*
1814*7c478bd9Sstevel@tonic-gate 	 * If the key is going down, and it's not one of the keys that doesn't
1815*7c478bd9Sstevel@tonic-gate 	 * auto-repeat, set up the auto-repeat timeout.
1816*7c478bd9Sstevel@tonic-gate 	 *
1817*7c478bd9Sstevel@tonic-gate 	 * The keys that don't auto-repeat are the Compose key,
1818*7c478bd9Sstevel@tonic-gate 	 * the shift keys, the "bucky bit" keys, the "floating accent" keys,
1819*7c478bd9Sstevel@tonic-gate 	 * and the function keys when in TR_EVENT mode.
1820*7c478bd9Sstevel@tonic-gate 	 */
1821*7c478bd9Sstevel@tonic-gate 	if (newstate == PRESSED && entrytype != (SHIFTKEYS >> 8) &&
1822*7c478bd9Sstevel@tonic-gate 	    entrytype != (BUCKYBITS >> 8) && entrytype != (FUNNY >> 8) &&
1823*7c478bd9Sstevel@tonic-gate 	    entrytype != (FA_CLASS >> 8) &&
1824*7c478bd9Sstevel@tonic-gate 	    !((entrytype == (FUNCKEYS >> 8) || entrytype == (PADKEYS >> 8)) &&
1825*7c478bd9Sstevel@tonic-gate 	    kbdd->kbdd_translate == TR_EVENT)) {
1826*7c478bd9Sstevel@tonic-gate 		if (k->k_rptkey != keycode) {
1827*7c478bd9Sstevel@tonic-gate 			kbdcancelrpt(kbdd);
1828*7c478bd9Sstevel@tonic-gate 			kbdd->kbdd_rptid = qtimeout(q, kbdrpt, kbdd,
1829*7c478bd9Sstevel@tonic-gate 			    kbd_repeatdelay);
1830*7c478bd9Sstevel@tonic-gate 			k->k_rptkey = keycode;
1831*7c478bd9Sstevel@tonic-gate 		}
1832*7c478bd9Sstevel@tonic-gate 	} else if (key == KEYOF(k->k_rptkey))		/* key going up */
1833*7c478bd9Sstevel@tonic-gate 		kbdcancelrpt(kbdd);
1834*7c478bd9Sstevel@tonic-gate 	if ((newstate == RELEASED) && (kbdd->kbdd_translate == TR_EVENT))
1835*7c478bd9Sstevel@tonic-gate 		kbdkeyreleased(kbdd, key);
1836*7c478bd9Sstevel@tonic-gate 
1837*7c478bd9Sstevel@tonic-gate 	/*
1838*7c478bd9Sstevel@tonic-gate 	 * We assume here that keys other than shift keys and bucky keys have
1839*7c478bd9Sstevel@tonic-gate 	 * entries in the "up" table that cause nothing to be done, and thus we
1840*7c478bd9Sstevel@tonic-gate 	 * don't have to check for newstate == RELEASED.
1841*7c478bd9Sstevel@tonic-gate 	 */
1842*7c478bd9Sstevel@tonic-gate 	switch (entrytype) {
1843*7c478bd9Sstevel@tonic-gate 
1844*7c478bd9Sstevel@tonic-gate 	case 0x0:		/* regular key */
1845*7c478bd9Sstevel@tonic-gate 		switch (kbdd->kbdd_translate) {
1846*7c478bd9Sstevel@tonic-gate 
1847*7c478bd9Sstevel@tonic-gate 		case TR_EVENT:
1848*7c478bd9Sstevel@tonic-gate 			fe.id = entry | k->k_buckybits;
1849*7c478bd9Sstevel@tonic-gate 			fe.value = 1;
1850*7c478bd9Sstevel@tonic-gate 			kbdkeypressed(kbdd, key, &fe, entry);
1851*7c478bd9Sstevel@tonic-gate 			break;
1852*7c478bd9Sstevel@tonic-gate 
1853*7c478bd9Sstevel@tonic-gate 		case TR_ASCII:
1854*7c478bd9Sstevel@tonic-gate 			kbdputcode(entry | k->k_buckybits, q);
1855*7c478bd9Sstevel@tonic-gate 			break;
1856*7c478bd9Sstevel@tonic-gate 		}
1857*7c478bd9Sstevel@tonic-gate 		break;
1858*7c478bd9Sstevel@tonic-gate 
1859*7c478bd9Sstevel@tonic-gate 	case SHIFTKEYS >> 8: {
1860*7c478bd9Sstevel@tonic-gate 		uint_t shiftbit = 1 << (entry & 0x0F);
1861*7c478bd9Sstevel@tonic-gate 
1862*7c478bd9Sstevel@tonic-gate 		/* Modify toggle state (see toggle processing above) */
1863*7c478bd9Sstevel@tonic-gate 		if (shiftbit & k->k_curkeyboard->k_toggleshifts) {
1864*7c478bd9Sstevel@tonic-gate 			if (newstate == RELEASED) {
1865*7c478bd9Sstevel@tonic-gate 				if (shiftbit == CAPSMASK) {
1866*7c478bd9Sstevel@tonic-gate 					kbdd->led_state &= ~LED_CAPS_LOCK;
1867*7c478bd9Sstevel@tonic-gate 					kbdsetled(kbdd);
1868*7c478bd9Sstevel@tonic-gate 				} else if (shiftbit == NUMLOCKMASK) {
1869*7c478bd9Sstevel@tonic-gate 					kbdd->led_state &= ~LED_NUM_LOCK;
1870*7c478bd9Sstevel@tonic-gate 					kbdsetled(kbdd);
1871*7c478bd9Sstevel@tonic-gate 				}
1872*7c478bd9Sstevel@tonic-gate 				k->k_togglemask &= ~shiftbit;
1873*7c478bd9Sstevel@tonic-gate 			} else {
1874*7c478bd9Sstevel@tonic-gate 				if (shiftbit == CAPSMASK) {
1875*7c478bd9Sstevel@tonic-gate 					kbdd->led_state |= LED_CAPS_LOCK;
1876*7c478bd9Sstevel@tonic-gate 					kbdsetled(kbdd);
1877*7c478bd9Sstevel@tonic-gate 				} else if (shiftbit == NUMLOCKMASK) {
1878*7c478bd9Sstevel@tonic-gate 					kbdd->led_state |= LED_NUM_LOCK;
1879*7c478bd9Sstevel@tonic-gate 					kbdsetled(kbdd);
1880*7c478bd9Sstevel@tonic-gate 				}
1881*7c478bd9Sstevel@tonic-gate 				k->k_togglemask |= shiftbit;
1882*7c478bd9Sstevel@tonic-gate 			}
1883*7c478bd9Sstevel@tonic-gate 		}
1884*7c478bd9Sstevel@tonic-gate 
1885*7c478bd9Sstevel@tonic-gate 		if (newstate == RELEASED)
1886*7c478bd9Sstevel@tonic-gate 			k->k_shiftmask &= ~shiftbit;
1887*7c478bd9Sstevel@tonic-gate 		else
1888*7c478bd9Sstevel@tonic-gate 			k->k_shiftmask |= shiftbit;
1889*7c478bd9Sstevel@tonic-gate 
1890*7c478bd9Sstevel@tonic-gate 		if (kbdd->kbdd_translate == TR_EVENT && newstate == PRESSED) {
1891*7c478bd9Sstevel@tonic-gate 			/*
1892*7c478bd9Sstevel@tonic-gate 			 * Relying on ordinal correspondence between
1893*7c478bd9Sstevel@tonic-gate 			 * vuid_event.h SHIFT_CAPSLOCK-SHIFT_RIGHTCTRL &
1894*7c478bd9Sstevel@tonic-gate 			 * kbd.h CAPSLOCK-RIGHTCTRL in order to
1895*7c478bd9Sstevel@tonic-gate 			 * correctly translate entry into fe.id.
1896*7c478bd9Sstevel@tonic-gate 			 */
1897*7c478bd9Sstevel@tonic-gate 			fe.id = SHIFT_CAPSLOCK + (entry & 0x0F);
1898*7c478bd9Sstevel@tonic-gate 			fe.value = 1;
1899*7c478bd9Sstevel@tonic-gate 			kbdkeypressed(kbdd, key, &fe, fe.id);
1900*7c478bd9Sstevel@tonic-gate 		}
1901*7c478bd9Sstevel@tonic-gate 		break;
1902*7c478bd9Sstevel@tonic-gate 		}
1903*7c478bd9Sstevel@tonic-gate 
1904*7c478bd9Sstevel@tonic-gate 	case BUCKYBITS >> 8:
1905*7c478bd9Sstevel@tonic-gate 		k->k_buckybits ^= 1 << (7 + (entry & 0x0F));
1906*7c478bd9Sstevel@tonic-gate 		if (kbdd->kbdd_translate == TR_EVENT && newstate == PRESSED) {
1907*7c478bd9Sstevel@tonic-gate 			/*
1908*7c478bd9Sstevel@tonic-gate 			 * Relying on ordinal correspondence between
1909*7c478bd9Sstevel@tonic-gate 			 * vuid_event.h SHIFT_META-SHIFT_TOP &
1910*7c478bd9Sstevel@tonic-gate 			 * kbd.h METABIT-SYSTEMBIT in order to
1911*7c478bd9Sstevel@tonic-gate 			 * correctly translate entry into fe.id.
1912*7c478bd9Sstevel@tonic-gate 			 */
1913*7c478bd9Sstevel@tonic-gate 			fe.id = SHIFT_META + (entry & 0x0F);
1914*7c478bd9Sstevel@tonic-gate 			fe.value = 1;
1915*7c478bd9Sstevel@tonic-gate 			kbdkeypressed(kbdd, key, &fe, fe.id);
1916*7c478bd9Sstevel@tonic-gate 		}
1917*7c478bd9Sstevel@tonic-gate 		break;
1918*7c478bd9Sstevel@tonic-gate 
1919*7c478bd9Sstevel@tonic-gate 	case FUNNY >> 8:
1920*7c478bd9Sstevel@tonic-gate 		switch (entry) {
1921*7c478bd9Sstevel@tonic-gate 		case NOP:
1922*7c478bd9Sstevel@tonic-gate 			break;
1923*7c478bd9Sstevel@tonic-gate 
1924*7c478bd9Sstevel@tonic-gate 		case IDLE:
1925*7c478bd9Sstevel@tonic-gate 			/* Fall thru into RESET code */
1926*7c478bd9Sstevel@tonic-gate 			/* FALLTHRU */
1927*7c478bd9Sstevel@tonic-gate 		case RESET:
1928*7c478bd9Sstevel@tonic-gate 		gotreset:
1929*7c478bd9Sstevel@tonic-gate 			k->k_shiftmask &= k->k_curkeyboard->k_idleshifts;
1930*7c478bd9Sstevel@tonic-gate 			k->k_shiftmask |= k->k_togglemask;
1931*7c478bd9Sstevel@tonic-gate 			k->k_buckybits &= k->k_curkeyboard->k_idlebuckys;
1932*7c478bd9Sstevel@tonic-gate 			kbdcancelrpt(kbdd);
1933*7c478bd9Sstevel@tonic-gate 			kbdreleaseall(kbdd);
1934*7c478bd9Sstevel@tonic-gate 			break;
1935*7c478bd9Sstevel@tonic-gate 
1936*7c478bd9Sstevel@tonic-gate 		case ERROR:
1937*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "kbd: Error detected");
1938*7c478bd9Sstevel@tonic-gate 			goto gotreset;
1939*7c478bd9Sstevel@tonic-gate 
1940*7c478bd9Sstevel@tonic-gate 		case COMPOSE:
1941*7c478bd9Sstevel@tonic-gate 			k->k_state = COMPOSE1;
1942*7c478bd9Sstevel@tonic-gate 			kbdd->led_state |= LED_COMPOSE;
1943*7c478bd9Sstevel@tonic-gate 			kbdsetled(kbdd);
1944*7c478bd9Sstevel@tonic-gate 			break;
1945*7c478bd9Sstevel@tonic-gate 		/*
1946*7c478bd9Sstevel@tonic-gate 		 * Remember when adding new entries that,
1947*7c478bd9Sstevel@tonic-gate 		 * if they should NOT auto-repeat,
1948*7c478bd9Sstevel@tonic-gate 		 * they should be put into the IF statement
1949*7c478bd9Sstevel@tonic-gate 		 * just above this switch block.
1950*7c478bd9Sstevel@tonic-gate 		 */
1951*7c478bd9Sstevel@tonic-gate 		default:
1952*7c478bd9Sstevel@tonic-gate 			goto badentry;
1953*7c478bd9Sstevel@tonic-gate 		}
1954*7c478bd9Sstevel@tonic-gate 		break;
1955*7c478bd9Sstevel@tonic-gate 
1956*7c478bd9Sstevel@tonic-gate 	case FA_CLASS >> 8:
1957*7c478bd9Sstevel@tonic-gate 		if (k->k_state == NORMAL) {
1958*7c478bd9Sstevel@tonic-gate 			kbdd->fltaccent_entry = entry;
1959*7c478bd9Sstevel@tonic-gate 			k->k_state = FLTACCENT;
1960*7c478bd9Sstevel@tonic-gate 		}
1961*7c478bd9Sstevel@tonic-gate 		return;
1962*7c478bd9Sstevel@tonic-gate 
1963*7c478bd9Sstevel@tonic-gate 	case STRING >> 8:
1964*7c478bd9Sstevel@tonic-gate 		cp = &keystringtab[entry & 0x0F][0];
1965*7c478bd9Sstevel@tonic-gate 		while (*cp != '\0') {
1966*7c478bd9Sstevel@tonic-gate 			switch (kbdd->kbdd_translate) {
1967*7c478bd9Sstevel@tonic-gate 
1968*7c478bd9Sstevel@tonic-gate 			case TR_EVENT:
1969*7c478bd9Sstevel@tonic-gate 				kbd_send_esc_event(*cp, kbdd);
1970*7c478bd9Sstevel@tonic-gate 				break;
1971*7c478bd9Sstevel@tonic-gate 
1972*7c478bd9Sstevel@tonic-gate 			case TR_ASCII:
1973*7c478bd9Sstevel@tonic-gate 				kbdputcode((uchar_t)*cp, q);
1974*7c478bd9Sstevel@tonic-gate 				break;
1975*7c478bd9Sstevel@tonic-gate 			}
1976*7c478bd9Sstevel@tonic-gate 			cp++;
1977*7c478bd9Sstevel@tonic-gate 		}
1978*7c478bd9Sstevel@tonic-gate 		break;
1979*7c478bd9Sstevel@tonic-gate 
1980*7c478bd9Sstevel@tonic-gate 	case FUNCKEYS >> 8:
1981*7c478bd9Sstevel@tonic-gate 		switch (kbdd->kbdd_translate) {
1982*7c478bd9Sstevel@tonic-gate 
1983*7c478bd9Sstevel@tonic-gate 		case TR_ASCII:
1984*7c478bd9Sstevel@tonic-gate 			bufp = buf;
1985*7c478bd9Sstevel@tonic-gate 			cp = strsetwithdecimal(bufp + 2,
1986*7c478bd9Sstevel@tonic-gate 				(uint_t)((entry & 0x003F) + 192),
1987*7c478bd9Sstevel@tonic-gate 				sizeof (buf) - 5);
1988*7c478bd9Sstevel@tonic-gate 			*bufp++ = '\033'; /* Escape */
1989*7c478bd9Sstevel@tonic-gate 			*bufp++ = '[';
1990*7c478bd9Sstevel@tonic-gate 			while (*cp != '\0')
1991*7c478bd9Sstevel@tonic-gate 				*bufp++ = *cp++;
1992*7c478bd9Sstevel@tonic-gate 			*bufp++ = 'z';
1993*7c478bd9Sstevel@tonic-gate 			*bufp = '\0';
1994*7c478bd9Sstevel@tonic-gate 			kbdputbuf(buf, q);
1995*7c478bd9Sstevel@tonic-gate 			break;
1996*7c478bd9Sstevel@tonic-gate 
1997*7c478bd9Sstevel@tonic-gate 		case TR_EVENT:
1998*7c478bd9Sstevel@tonic-gate 			/*
1999*7c478bd9Sstevel@tonic-gate 			 * Take advantage of the similar
2000*7c478bd9Sstevel@tonic-gate 			 * ordering of kbd.h function keys and
2001*7c478bd9Sstevel@tonic-gate 			 * vuid_event.h function keys to do a
2002*7c478bd9Sstevel@tonic-gate 			 * simple translation to achieve a
2003*7c478bd9Sstevel@tonic-gate 			 * mapping between the 2 different
2004*7c478bd9Sstevel@tonic-gate 			 * address spaces.
2005*7c478bd9Sstevel@tonic-gate 			 */
2006*7c478bd9Sstevel@tonic-gate 			fe.id = (entry & 0x003F) + KEY_LEFTFIRST;
2007*7c478bd9Sstevel@tonic-gate 			fe.value = 1;
2008*7c478bd9Sstevel@tonic-gate 			/*
2009*7c478bd9Sstevel@tonic-gate 			 * Assume "up" table only generates
2010*7c478bd9Sstevel@tonic-gate 			 * shift changes.
2011*7c478bd9Sstevel@tonic-gate 			 */
2012*7c478bd9Sstevel@tonic-gate 			kbdkeypressed(kbdd, key, &fe, fe.id);
2013*7c478bd9Sstevel@tonic-gate 			/*
2014*7c478bd9Sstevel@tonic-gate 			 * Function key events can be expanded
2015*7c478bd9Sstevel@tonic-gate 			 * by terminal emulator software to
2016*7c478bd9Sstevel@tonic-gate 			 * produce the standard escape sequence
2017*7c478bd9Sstevel@tonic-gate 			 * generated by the TR_ASCII case above
2018*7c478bd9Sstevel@tonic-gate 			 * if a function key event is not used
2019*7c478bd9Sstevel@tonic-gate 			 * by terminal emulator software
2020*7c478bd9Sstevel@tonic-gate 			 * directly.
2021*7c478bd9Sstevel@tonic-gate 			 */
2022*7c478bd9Sstevel@tonic-gate 			break;
2023*7c478bd9Sstevel@tonic-gate 		}
2024*7c478bd9Sstevel@tonic-gate 		break;
2025*7c478bd9Sstevel@tonic-gate 
2026*7c478bd9Sstevel@tonic-gate 	/*
2027*7c478bd9Sstevel@tonic-gate 	 * Remember when adding new entries that,
2028*7c478bd9Sstevel@tonic-gate 	 * if they should NOT auto-repeat,
2029*7c478bd9Sstevel@tonic-gate 	 * they should be put into the IF statement
2030*7c478bd9Sstevel@tonic-gate 	 * just above this switch block.
2031*7c478bd9Sstevel@tonic-gate 	 */
2032*7c478bd9Sstevel@tonic-gate 	case PADKEYS >> 8:
2033*7c478bd9Sstevel@tonic-gate 		switch (kbdd->kbdd_translate) {
2034*7c478bd9Sstevel@tonic-gate 
2035*7c478bd9Sstevel@tonic-gate 		case TR_ASCII:
2036*7c478bd9Sstevel@tonic-gate 			kbdputcode(kb_numlock_table[entry&0x1F], q);
2037*7c478bd9Sstevel@tonic-gate 			break;
2038*7c478bd9Sstevel@tonic-gate 
2039*7c478bd9Sstevel@tonic-gate 		case TR_EVENT:
2040*7c478bd9Sstevel@tonic-gate 			/*
2041*7c478bd9Sstevel@tonic-gate 			 * Take advantage of the similar
2042*7c478bd9Sstevel@tonic-gate 			 * ordering of kbd.h keypad keys and
2043*7c478bd9Sstevel@tonic-gate 			 * vuid_event.h keypad keys to do a
2044*7c478bd9Sstevel@tonic-gate 			 * simple translation to achieve a
2045*7c478bd9Sstevel@tonic-gate 			 * mapping between the 2 different
2046*7c478bd9Sstevel@tonic-gate 			 * address spaces.
2047*7c478bd9Sstevel@tonic-gate 			 */
2048*7c478bd9Sstevel@tonic-gate 			fe.id = (entry & 0x001F) + VKEY_FIRSTPAD;
2049*7c478bd9Sstevel@tonic-gate 			fe.value = 1;
2050*7c478bd9Sstevel@tonic-gate 			/*
2051*7c478bd9Sstevel@tonic-gate 			 * Assume "up" table only generates
2052*7c478bd9Sstevel@tonic-gate 			 * shift changes.
2053*7c478bd9Sstevel@tonic-gate 			 */
2054*7c478bd9Sstevel@tonic-gate 			kbdkeypressed(kbdd, key, &fe, fe.id);
2055*7c478bd9Sstevel@tonic-gate 			/*
2056*7c478bd9Sstevel@tonic-gate 			 * Keypad key events can be expanded
2057*7c478bd9Sstevel@tonic-gate 			 * by terminal emulator software to
2058*7c478bd9Sstevel@tonic-gate 			 * produce the standard ascii character
2059*7c478bd9Sstevel@tonic-gate 			 * generated by the TR_ASCII case above
2060*7c478bd9Sstevel@tonic-gate 			 * if a keypad key event is not used
2061*7c478bd9Sstevel@tonic-gate 			 * by terminal emulator software
2062*7c478bd9Sstevel@tonic-gate 			 * directly.
2063*7c478bd9Sstevel@tonic-gate 			 */
2064*7c478bd9Sstevel@tonic-gate 			break;
2065*7c478bd9Sstevel@tonic-gate 		}
2066*7c478bd9Sstevel@tonic-gate 
2067*7c478bd9Sstevel@tonic-gate 	badentry:
2068*7c478bd9Sstevel@tonic-gate 		break;
2069*7c478bd9Sstevel@tonic-gate 	}
2070*7c478bd9Sstevel@tonic-gate }
2071*7c478bd9Sstevel@tonic-gate 
2072*7c478bd9Sstevel@tonic-gate static int
2073*7c478bd9Sstevel@tonic-gate kbd_do_compose(ushort_t first_entry, ushort_t second_entry,
2074*7c478bd9Sstevel@tonic-gate 	ushort_t *result_iso_ptr)
2075*7c478bd9Sstevel@tonic-gate {
2076*7c478bd9Sstevel@tonic-gate 	struct compose_sequence_t *ptr;
2077*7c478bd9Sstevel@tonic-gate 
2078*7c478bd9Sstevel@tonic-gate 	ptr = &kb_compose_table[kb_compose_map[first_entry]];
2079*7c478bd9Sstevel@tonic-gate 	while (ptr->first == first_entry) {
2080*7c478bd9Sstevel@tonic-gate 		if (ptr->second == second_entry) {
2081*7c478bd9Sstevel@tonic-gate 			*result_iso_ptr = ptr->iso;
2082*7c478bd9Sstevel@tonic-gate 			return (1);
2083*7c478bd9Sstevel@tonic-gate 		}
2084*7c478bd9Sstevel@tonic-gate 		ptr++;
2085*7c478bd9Sstevel@tonic-gate 	}
2086*7c478bd9Sstevel@tonic-gate 	return (0);
2087*7c478bd9Sstevel@tonic-gate }
2088*7c478bd9Sstevel@tonic-gate 
2089*7c478bd9Sstevel@tonic-gate static void
2090*7c478bd9Sstevel@tonic-gate kbd_send_esc_event(char c, register struct kbddata *kbdd)
2091*7c478bd9Sstevel@tonic-gate {
2092*7c478bd9Sstevel@tonic-gate 	Firm_event fe;
2093*7c478bd9Sstevel@tonic-gate 
2094*7c478bd9Sstevel@tonic-gate 	fe.id = c;
2095*7c478bd9Sstevel@tonic-gate 	fe.value = 1;
2096*7c478bd9Sstevel@tonic-gate 	fe.pair_type = FE_PAIR_NONE;
2097*7c478bd9Sstevel@tonic-gate 	fe.pair = 0;
2098*7c478bd9Sstevel@tonic-gate 	/*
2099*7c478bd9Sstevel@tonic-gate 	 * Pretend as if each cp pushed and released
2100*7c478bd9Sstevel@tonic-gate 	 * Calling kbdqueueevent avoids addr translation
2101*7c478bd9Sstevel@tonic-gate 	 * and pair base determination of kbdkeypressed.
2102*7c478bd9Sstevel@tonic-gate 	 */
2103*7c478bd9Sstevel@tonic-gate 	kbdqueueevent(kbdd, &fe);
2104*7c478bd9Sstevel@tonic-gate 	fe.value = 0;
2105*7c478bd9Sstevel@tonic-gate 	kbdqueueevent(kbdd, &fe);
2106*7c478bd9Sstevel@tonic-gate }
2107*7c478bd9Sstevel@tonic-gate 
2108*7c478bd9Sstevel@tonic-gate char *
2109*7c478bd9Sstevel@tonic-gate strsetwithdecimal(char *buf, uint_t val, uint_t maxdigs)
2110*7c478bd9Sstevel@tonic-gate {
2111*7c478bd9Sstevel@tonic-gate 	int	hradix = 5;
2112*7c478bd9Sstevel@tonic-gate 	char	*bp;
2113*7c478bd9Sstevel@tonic-gate 	int	lowbit;
2114*7c478bd9Sstevel@tonic-gate 	char	*tab = "0123456789abcdef";
2115*7c478bd9Sstevel@tonic-gate 
2116*7c478bd9Sstevel@tonic-gate 	bp = buf + maxdigs;
2117*7c478bd9Sstevel@tonic-gate 	*(--bp) = '\0';
2118*7c478bd9Sstevel@tonic-gate 	while (val) {
2119*7c478bd9Sstevel@tonic-gate 		lowbit = val & 1;
2120*7c478bd9Sstevel@tonic-gate 		val = (val >> 1);
2121*7c478bd9Sstevel@tonic-gate 		*(--bp) = tab[val % hradix * 2 + lowbit];
2122*7c478bd9Sstevel@tonic-gate 		val /= hradix;
2123*7c478bd9Sstevel@tonic-gate 	}
2124*7c478bd9Sstevel@tonic-gate 	return (bp);
2125*7c478bd9Sstevel@tonic-gate }
2126*7c478bd9Sstevel@tonic-gate 
2127*7c478bd9Sstevel@tonic-gate static void
2128*7c478bd9Sstevel@tonic-gate kbdkeypressed(struct kbddata *kbdd, uchar_t key_station, Firm_event *fe,
2129*7c478bd9Sstevel@tonic-gate     ushort_t base)
2130*7c478bd9Sstevel@tonic-gate {
2131*7c478bd9Sstevel@tonic-gate 	register struct keyboardstate *k;
2132*7c478bd9Sstevel@tonic-gate 	register short id_addr;
2133*7c478bd9Sstevel@tonic-gate 
2134*7c478bd9Sstevel@tonic-gate 	/* Set pair values */
2135*7c478bd9Sstevel@tonic-gate 	if (fe->id < (ushort_t)VKEY_FIRST) {
2136*7c478bd9Sstevel@tonic-gate 		/*
2137*7c478bd9Sstevel@tonic-gate 		 * If CTRLed, find the ID that would have been used had it
2138*7c478bd9Sstevel@tonic-gate 		 * not been CTRLed.
2139*7c478bd9Sstevel@tonic-gate 		 */
2140*7c478bd9Sstevel@tonic-gate 		k = &kbdd->kbdd_state;
2141*7c478bd9Sstevel@tonic-gate 		if (k->k_shiftmask & (CTRLMASK | CTLSMASK)) {
2142*7c478bd9Sstevel@tonic-gate 			struct keymap *km;
2143*7c478bd9Sstevel@tonic-gate 
2144*7c478bd9Sstevel@tonic-gate 			km = settable(kbdd,
2145*7c478bd9Sstevel@tonic-gate 			    k->k_shiftmask & ~(CTRLMASK | CTLSMASK | UPMASK));
2146*7c478bd9Sstevel@tonic-gate 			if (km == NULL)
2147*7c478bd9Sstevel@tonic-gate 				return;
2148*7c478bd9Sstevel@tonic-gate 			base = km->keymap[key_station];
2149*7c478bd9Sstevel@tonic-gate 		}
2150*7c478bd9Sstevel@tonic-gate 		if (base != fe->id) {
2151*7c478bd9Sstevel@tonic-gate 			fe->pair_type = FE_PAIR_SET;
2152*7c478bd9Sstevel@tonic-gate 			fe->pair = base;
2153*7c478bd9Sstevel@tonic-gate 			goto send;
2154*7c478bd9Sstevel@tonic-gate 		}
2155*7c478bd9Sstevel@tonic-gate 	}
2156*7c478bd9Sstevel@tonic-gate 	fe->pair_type = FE_PAIR_NONE;
2157*7c478bd9Sstevel@tonic-gate 	fe->pair = 0;
2158*7c478bd9Sstevel@tonic-gate send:
2159*7c478bd9Sstevel@tonic-gate 	/* Adjust event id address for multiple keyboard/workstation support */
2160*7c478bd9Sstevel@tonic-gate 	switch (vuid_id_addr(fe->id)) {
2161*7c478bd9Sstevel@tonic-gate 	case ASCII_FIRST:
2162*7c478bd9Sstevel@tonic-gate 		id_addr = kbdd->kbdd_ascii_addr;
2163*7c478bd9Sstevel@tonic-gate 		break;
2164*7c478bd9Sstevel@tonic-gate 	case TOP_FIRST:
2165*7c478bd9Sstevel@tonic-gate 		id_addr = kbdd->kbdd_top_addr;
2166*7c478bd9Sstevel@tonic-gate 		break;
2167*7c478bd9Sstevel@tonic-gate 	case VKEY_FIRST:
2168*7c478bd9Sstevel@tonic-gate 		id_addr = kbdd->kbdd_vkey_addr;
2169*7c478bd9Sstevel@tonic-gate 		break;
2170*7c478bd9Sstevel@tonic-gate 	default:
2171*7c478bd9Sstevel@tonic-gate 		id_addr = vuid_id_addr(fe->id);
2172*7c478bd9Sstevel@tonic-gate 	}
2173*7c478bd9Sstevel@tonic-gate 	fe->id = vuid_id_offset(fe->id) | id_addr;
2174*7c478bd9Sstevel@tonic-gate 	kbdqueuepress(kbdd, key_station, fe);
2175*7c478bd9Sstevel@tonic-gate }
2176*7c478bd9Sstevel@tonic-gate 
2177*7c478bd9Sstevel@tonic-gate static void
2178*7c478bd9Sstevel@tonic-gate kbdqueuepress(struct kbddata *kbdd, uchar_t key_station, Firm_event *fe)
2179*7c478bd9Sstevel@tonic-gate {
2180*7c478bd9Sstevel@tonic-gate 	register struct key_event *ke, *ke_free;
2181*7c478bd9Sstevel@tonic-gate 	register int i;
2182*7c478bd9Sstevel@tonic-gate 
2183*7c478bd9Sstevel@tonic-gate 	if (key_station == IDLEKEY)
2184*7c478bd9Sstevel@tonic-gate 		return;
2185*7c478bd9Sstevel@tonic-gate #ifdef	KBD_DEBUG
2186*7c478bd9Sstevel@tonic-gate 	if (kbd_input_debug) printf("KBD PRESSED key=%d\n", key_station);
2187*7c478bd9Sstevel@tonic-gate #endif
2188*7c478bd9Sstevel@tonic-gate 	ke_free = 0;
2189*7c478bd9Sstevel@tonic-gate 	/* Scan table of down key stations */
2190*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_translate == TR_EVENT ||
2191*7c478bd9Sstevel@tonic-gate 	    kbdd->kbdd_translate == TR_UNTRANS_EVENT) {
2192*7c478bd9Sstevel@tonic-gate 		for (i = 0, ke = kbdd->kbdd_downs;
2193*7c478bd9Sstevel@tonic-gate 		    i < kbdd->kbdd_downs_entries;
2194*7c478bd9Sstevel@tonic-gate 		    i++, ke++) {
2195*7c478bd9Sstevel@tonic-gate 			/* Keycode already down? */
2196*7c478bd9Sstevel@tonic-gate 			if (ke->key_station == key_station) {
2197*7c478bd9Sstevel@tonic-gate #ifdef	KBD_DEBUG
2198*7c478bd9Sstevel@tonic-gate 	printf("kbd: Double entry in downs table (%d,%d)!\n", key_station, i);
2199*7c478bd9Sstevel@tonic-gate #endif
2200*7c478bd9Sstevel@tonic-gate 				goto add_event;
2201*7c478bd9Sstevel@tonic-gate 			}
2202*7c478bd9Sstevel@tonic-gate 			if (ke->key_station == 0)
2203*7c478bd9Sstevel@tonic-gate 				ke_free = ke;
2204*7c478bd9Sstevel@tonic-gate 		}
2205*7c478bd9Sstevel@tonic-gate 		if (ke_free) {
2206*7c478bd9Sstevel@tonic-gate 			ke = ke_free;
2207*7c478bd9Sstevel@tonic-gate 			goto add_event;
2208*7c478bd9Sstevel@tonic-gate 		}
2209*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "kbd: Too many keys down!");
2210*7c478bd9Sstevel@tonic-gate 		ke = kbdd->kbdd_downs;
2211*7c478bd9Sstevel@tonic-gate 	}
2212*7c478bd9Sstevel@tonic-gate add_event:
2213*7c478bd9Sstevel@tonic-gate 	ke->key_station = key_station;
2214*7c478bd9Sstevel@tonic-gate 	ke->event = *fe;
2215*7c478bd9Sstevel@tonic-gate 	kbdqueueevent(kbdd, fe);
2216*7c478bd9Sstevel@tonic-gate }
2217*7c478bd9Sstevel@tonic-gate 
2218*7c478bd9Sstevel@tonic-gate static void
2219*7c478bd9Sstevel@tonic-gate kbdkeyreleased(register struct kbddata *kbdd, uchar_t key_station)
2220*7c478bd9Sstevel@tonic-gate {
2221*7c478bd9Sstevel@tonic-gate 	register struct key_event *ke;
2222*7c478bd9Sstevel@tonic-gate 	register int i;
2223*7c478bd9Sstevel@tonic-gate 
2224*7c478bd9Sstevel@tonic-gate 	if (key_station == IDLEKEY)
2225*7c478bd9Sstevel@tonic-gate 		return;
2226*7c478bd9Sstevel@tonic-gate #ifdef	KBD_DEBUG
2227*7c478bd9Sstevel@tonic-gate 	if (kbd_input_debug)
2228*7c478bd9Sstevel@tonic-gate 		printf("KBD RELEASE key=%d\n", key_station);
2229*7c478bd9Sstevel@tonic-gate #endif
2230*7c478bd9Sstevel@tonic-gate 	if (kbdd->kbdd_translate != TR_EVENT &&
2231*7c478bd9Sstevel@tonic-gate 	    kbdd->kbdd_translate != TR_UNTRANS_EVENT)
2232*7c478bd9Sstevel@tonic-gate 		return;
2233*7c478bd9Sstevel@tonic-gate 	/* Scan table of down key stations */
2234*7c478bd9Sstevel@tonic-gate 	for (i = 0, ke = kbdd->kbdd_downs;
2235*7c478bd9Sstevel@tonic-gate 	    i < kbdd->kbdd_downs_entries;
2236*7c478bd9Sstevel@tonic-gate 	    i++, ke++) {
2237*7c478bd9Sstevel@tonic-gate 		/* Found? */
2238*7c478bd9Sstevel@tonic-gate 		if (ke->key_station == key_station) {
2239*7c478bd9Sstevel@tonic-gate 			ke->key_station = 0;
2240*7c478bd9Sstevel@tonic-gate 			ke->event.value = 0;
2241*7c478bd9Sstevel@tonic-gate 			kbdqueueevent(kbdd, &ke->event);
2242*7c478bd9Sstevel@tonic-gate 		}
2243*7c478bd9Sstevel@tonic-gate 	}
2244*7c478bd9Sstevel@tonic-gate 
2245*7c478bd9Sstevel@tonic-gate 	/*
2246*7c478bd9Sstevel@tonic-gate 	 * Ignore if couldn't find because may be called twice
2247*7c478bd9Sstevel@tonic-gate 	 * for the same key station in the case of the kbdrpt
2248*7c478bd9Sstevel@tonic-gate 	 * routine being called unnecessarily.
2249*7c478bd9Sstevel@tonic-gate 	 */
2250*7c478bd9Sstevel@tonic-gate }
2251*7c478bd9Sstevel@tonic-gate 
2252*7c478bd9Sstevel@tonic-gate static void
2253*7c478bd9Sstevel@tonic-gate kbdreleaseall(struct kbddata *kbdd)
2254*7c478bd9Sstevel@tonic-gate {
2255*7c478bd9Sstevel@tonic-gate 	register struct key_event *ke;
2256*7c478bd9Sstevel@tonic-gate 	register int i;
2257*7c478bd9Sstevel@tonic-gate 
2258*7c478bd9Sstevel@tonic-gate #ifdef	KBD_DEBUG
2259*7c478bd9Sstevel@tonic-gate 	if (kbd_debug && kbd_ra_debug) printf("KBD RELEASE ALL\n");
2260*7c478bd9Sstevel@tonic-gate #endif
2261*7c478bd9Sstevel@tonic-gate 	/* Scan table of down key stations */
2262*7c478bd9Sstevel@tonic-gate 	for (i = 0, ke = kbdd->kbdd_downs;
2263*7c478bd9Sstevel@tonic-gate 	    i < kbdd->kbdd_downs_entries; i++, ke++) {
2264*7c478bd9Sstevel@tonic-gate 		/* Key station not zero */
2265*7c478bd9Sstevel@tonic-gate 		if (ke->key_station)
2266*7c478bd9Sstevel@tonic-gate 			kbdkeyreleased(kbdd, ke->key_station);
2267*7c478bd9Sstevel@tonic-gate 			/* kbdkeyreleased resets kbdd_downs entry */
2268*7c478bd9Sstevel@tonic-gate 	}
2269*7c478bd9Sstevel@tonic-gate }
2270*7c478bd9Sstevel@tonic-gate 
2271*7c478bd9Sstevel@tonic-gate /*
2272*7c478bd9Sstevel@tonic-gate  * Pass a keycode up the stream, if you can, otherwise throw it away.
2273*7c478bd9Sstevel@tonic-gate  */
2274*7c478bd9Sstevel@tonic-gate static void
2275*7c478bd9Sstevel@tonic-gate kbdputcode(uint_t code, queue_t *q)
2276*7c478bd9Sstevel@tonic-gate {
2277*7c478bd9Sstevel@tonic-gate 	register mblk_t *bp;
2278*7c478bd9Sstevel@tonic-gate 
2279*7c478bd9Sstevel@tonic-gate 	if (!canput(q))
2280*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "kbdputcode: Can't put block for keycode");
2281*7c478bd9Sstevel@tonic-gate 	else {
2282*7c478bd9Sstevel@tonic-gate 		if ((bp = allocb(sizeof (uint_t), BPRI_HI)) == NULL)
2283*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2284*7c478bd9Sstevel@tonic-gate 			    "kbdputcode: Can't allocate block for keycode");
2285*7c478bd9Sstevel@tonic-gate 		else {
2286*7c478bd9Sstevel@tonic-gate 			*bp->b_wptr++ = code;
2287*7c478bd9Sstevel@tonic-gate 			putnext(q, bp);
2288*7c478bd9Sstevel@tonic-gate 		}
2289*7c478bd9Sstevel@tonic-gate 	}
2290*7c478bd9Sstevel@tonic-gate }
2291*7c478bd9Sstevel@tonic-gate 
2292*7c478bd9Sstevel@tonic-gate /*
2293*7c478bd9Sstevel@tonic-gate  * Pass  generated keycode sequence to upstream, if possible.
2294*7c478bd9Sstevel@tonic-gate  */
2295*7c478bd9Sstevel@tonic-gate static void
2296*7c478bd9Sstevel@tonic-gate kbdputbuf(char *buf, queue_t *q)
2297*7c478bd9Sstevel@tonic-gate {
2298*7c478bd9Sstevel@tonic-gate 	register mblk_t *bp;
2299*7c478bd9Sstevel@tonic-gate 
2300*7c478bd9Sstevel@tonic-gate 	if (!canput(q))
2301*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "kbdputbuf: Can't put block for keycode");
2302*7c478bd9Sstevel@tonic-gate 	else {
2303*7c478bd9Sstevel@tonic-gate 		if ((bp = allocb((int)strlen(buf), BPRI_HI)) == NULL)
2304*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2305*7c478bd9Sstevel@tonic-gate 				"kbdputbuf: Can't allocate block for keycode");
2306*7c478bd9Sstevel@tonic-gate 		else {
2307*7c478bd9Sstevel@tonic-gate 			while (*buf) {
2308*7c478bd9Sstevel@tonic-gate 				*bp->b_wptr++ = *buf;
2309*7c478bd9Sstevel@tonic-gate 				buf++;
2310*7c478bd9Sstevel@tonic-gate 			}
2311*7c478bd9Sstevel@tonic-gate 			putnext(q, bp);
2312*7c478bd9Sstevel@tonic-gate 		}
2313*7c478bd9Sstevel@tonic-gate 	}
2314*7c478bd9Sstevel@tonic-gate }
2315*7c478bd9Sstevel@tonic-gate 
2316*7c478bd9Sstevel@tonic-gate /*
2317*7c478bd9Sstevel@tonic-gate  * Pass a VUID "firm event" up the stream, if you can.
2318*7c478bd9Sstevel@tonic-gate  */
2319*7c478bd9Sstevel@tonic-gate static void
2320*7c478bd9Sstevel@tonic-gate kbdqueueevent(struct kbddata *kbdd, Firm_event *fe)
2321*7c478bd9Sstevel@tonic-gate {
2322*7c478bd9Sstevel@tonic-gate 	register queue_t *q;
2323*7c478bd9Sstevel@tonic-gate 	register mblk_t *bp;
2324*7c478bd9Sstevel@tonic-gate 
2325*7c478bd9Sstevel@tonic-gate 	if ((q = kbdd->kbdd_readq) == NULL)
2326*7c478bd9Sstevel@tonic-gate 		return;
2327*7c478bd9Sstevel@tonic-gate 	if (!canput(q)) {
2328*7c478bd9Sstevel@tonic-gate 		if (kbd_overflow_msg)
2329*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2330*7c478bd9Sstevel@tonic-gate 				"kbd: Buffer flushed when overflowed");
2331*7c478bd9Sstevel@tonic-gate 		kbdflush(kbdd);
2332*7c478bd9Sstevel@tonic-gate 		kbd_overflow_cnt++;
2333*7c478bd9Sstevel@tonic-gate 	} else {
2334*7c478bd9Sstevel@tonic-gate 		if ((bp = allocb(sizeof (Firm_event), BPRI_HI)) == NULL)
2335*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2336*7c478bd9Sstevel@tonic-gate 			    "kbdqueueevent: Can't allocate block for event");
2337*7c478bd9Sstevel@tonic-gate 		else {
2338*7c478bd9Sstevel@tonic-gate #if 1 /* XX64 */
2339*7c478bd9Sstevel@tonic-gate 			struct timeval now;
2340*7c478bd9Sstevel@tonic-gate 
2341*7c478bd9Sstevel@tonic-gate 			/*
2342*7c478bd9Sstevel@tonic-gate 			 * XX64: This is something of a compromise.  It
2343*7c478bd9Sstevel@tonic-gate 			 * seems justifiable based on the usage of these
2344*7c478bd9Sstevel@tonic-gate 			 * timestamps as an ordering relation as opposed
2345*7c478bd9Sstevel@tonic-gate 			 * to a strict timing thing.
2346*7c478bd9Sstevel@tonic-gate 			 *
2347*7c478bd9Sstevel@tonic-gate 			 * But should we restore Firm_event's time stamp
2348*7c478bd9Sstevel@tonic-gate 			 * to be a timeval, and send 32-bit and 64-bit
2349*7c478bd9Sstevel@tonic-gate 			 * events up the pipe?
2350*7c478bd9Sstevel@tonic-gate 			 */
2351*7c478bd9Sstevel@tonic-gate 			uniqtime(&now);
2352*7c478bd9Sstevel@tonic-gate 			TIMEVAL_TO_TIMEVAL32(&fe->time, &now);
2353*7c478bd9Sstevel@tonic-gate #else
2354*7c478bd9Sstevel@tonic-gate 			uniqtime(&fe->time);
2355*7c478bd9Sstevel@tonic-gate #endif
2356*7c478bd9Sstevel@tonic-gate 			*(Firm_event *)bp->b_wptr = *fe;
2357*7c478bd9Sstevel@tonic-gate 			bp->b_wptr += sizeof (Firm_event);
2358*7c478bd9Sstevel@tonic-gate 			putnext(q, bp);
2359*7c478bd9Sstevel@tonic-gate 		}
2360*7c478bd9Sstevel@tonic-gate 	}
2361*7c478bd9Sstevel@tonic-gate }
2362