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