xref: /onnv-gate/usr/src/uts/common/io/kb8042/kb8042.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 /*	Copyright (c) 1990, 1991 UNIX System Laboratories, Inc.	*/
23*0Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T	*/
24*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
25*0Sstevel@tonic-gate 
26*0Sstevel@tonic-gate /*
27*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28*0Sstevel@tonic-gate  * Use is subject to license terms.
29*0Sstevel@tonic-gate  */
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <sys/types.h>
34*0Sstevel@tonic-gate #include <sys/errno.h>
35*0Sstevel@tonic-gate #include <sys/inline.h>
36*0Sstevel@tonic-gate #include <sys/termio.h>
37*0Sstevel@tonic-gate #include <sys/stropts.h>
38*0Sstevel@tonic-gate #include <sys/termios.h>
39*0Sstevel@tonic-gate #include <sys/stream.h>
40*0Sstevel@tonic-gate #include <sys/strtty.h>
41*0Sstevel@tonic-gate #include <sys/strsubr.h>
42*0Sstevel@tonic-gate #include <sys/strsun.h>
43*0Sstevel@tonic-gate #include <sys/ddi.h>
44*0Sstevel@tonic-gate #include <sys/sunddi.h>
45*0Sstevel@tonic-gate #include <sys/note.h>
46*0Sstevel@tonic-gate #include "sys/consdev.h"
47*0Sstevel@tonic-gate #include <sys/kbd.h>
48*0Sstevel@tonic-gate #include <sys/kbtrans.h>
49*0Sstevel@tonic-gate #include "kb8042.h"
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate #include <sys/i8042.h>
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate #include "sys/kbio.h"		/* for KIOCSLAYOUT */
54*0Sstevel@tonic-gate #include "sys/stat.h"
55*0Sstevel@tonic-gate #include "sys/reboot.h"
56*0Sstevel@tonic-gate #include <sys/promif.h>
57*0Sstevel@tonic-gate #include <sys/beep.h>
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate /*
60*0Sstevel@tonic-gate  * For any keyboard, there is a unique code describing the position
61*0Sstevel@tonic-gate  * of the key on a keyboard. We refer to the code as "station number".
62*0Sstevel@tonic-gate  * The following table is used to map the station numbers from ps2
63*0Sstevel@tonic-gate  * AT/XT keyboards to that of a USB one.
64*0Sstevel@tonic-gate  */
65*0Sstevel@tonic-gate static kbtrans_key_t keytab_pc2usb[KBTRANS_KEYNUMS_MAX] = {
66*0Sstevel@tonic-gate /*  0 */	0,	53,	30,	31,	32,	33,	34,	35,
67*0Sstevel@tonic-gate /*  8 */	36,	37,	38,	39,	45,	46,	137,	42,
68*0Sstevel@tonic-gate /* 16 */	43,	20,	26,	8,	21,	23,	28,	24,
69*0Sstevel@tonic-gate /* 24 */	12,	18,	19,	47,	48,	49,	57,	4,
70*0Sstevel@tonic-gate /* 32 */	22,	7,	9,	10,	11,	13,	14,	15,
71*0Sstevel@tonic-gate /* 40 */	51,	52,	50,	40,	225,	100,	29,	27,
72*0Sstevel@tonic-gate /* 48 */	6,	25,	5,	17,	16,	54,	55,	56,
73*0Sstevel@tonic-gate /* 56 */	135,	229,	224,	227,	226,	44,	230,	231,
74*0Sstevel@tonic-gate /* 64 */	228,	101,	0,	0,	0,	0,	0,	0,
75*0Sstevel@tonic-gate /* 72 */	0,	0,	0,	73,	76,	0,	0,	80,
76*0Sstevel@tonic-gate /* 80 */	74,	77,	0,	82,	81,	75,	78,	0,
77*0Sstevel@tonic-gate /* 88 */	0,	79,	83,	95,	92,	89,	0,	84,
78*0Sstevel@tonic-gate /* 96 */	96,	93,	90,	98,	85,	97,	94,	91,
79*0Sstevel@tonic-gate /* 104 */	99,	86,	87,	133,	88,	0,	41,	0,
80*0Sstevel@tonic-gate /* 112 */	58,	59,	60,	61,	62,	63,	64,	65,
81*0Sstevel@tonic-gate /* 120 */	66,	67,	68,	69,	70,	71,	72,	0,
82*0Sstevel@tonic-gate /* 128 */	0,	0,	0,	139,	138,	136,	0,	0,
83*0Sstevel@tonic-gate /* 136 */	0,	0,	0,	0,	0,	0,	0,	0,
84*0Sstevel@tonic-gate /* 144 */	0,	0,	0,	0,	0,	0,	0,	0,
85*0Sstevel@tonic-gate /* 152 */	0,	0,	0,	0,	0,	0,	0,	0,
86*0Sstevel@tonic-gate /* 160 */	0,	0,	0,	0,	0,	0,	0,	0,
87*0Sstevel@tonic-gate /* 168 */	0,	0,	0,	0,	0,	0,	0,	0,
88*0Sstevel@tonic-gate /* 176 */	0,	0,	0,	0,	0,	0,	0,	0,
89*0Sstevel@tonic-gate /* 184 */	0,	0,	0,	0,	0,	0,	0,	0,
90*0Sstevel@tonic-gate /* 192 */	0,	0,	0,	0,	0,	0,	0,	0,
91*0Sstevel@tonic-gate /* 200 */	0,	0,	0,	0,	0,	0,	0,	0,
92*0Sstevel@tonic-gate /* 208 */	0,	0,	0,	0,	0,	0,	0,	0,
93*0Sstevel@tonic-gate /* 216 */	0,	0,	0,	0,	0,	0,	0,	0,
94*0Sstevel@tonic-gate /* 224 */	0,	0,	0,	0,	0,	0,	0,	0,
95*0Sstevel@tonic-gate /* 232 */	0,	0,	0,	0,	0,	0,	0,	0,
96*0Sstevel@tonic-gate /* 240 */	0,	0,	0,	0,	0,	0,	0,	0,
97*0Sstevel@tonic-gate /* 248 */	0,	0,	0,	0
98*0Sstevel@tonic-gate };
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate /*
101*0Sstevel@tonic-gate  * DEBUG (or KD_DEBUG for just this module) turns on a flag called
102*0Sstevel@tonic-gate  * kb8042_enable_debug_hotkey.  If kb8042_enable_debug_hotkey is true,
103*0Sstevel@tonic-gate  * then the following hotkeys are enabled:
104*0Sstevel@tonic-gate  *    F10 - turn on debugging "normal" translations
105*0Sstevel@tonic-gate  *    F9  - turn on debugging "getchar" translations
106*0Sstevel@tonic-gate  *    F8  - turn on "low level" debugging
107*0Sstevel@tonic-gate  *    F7  - turn on terse press/release debugging
108*0Sstevel@tonic-gate  *    F1  - turn off all debugging
109*0Sstevel@tonic-gate  * The default value for kb8042_enable_debug_hotkey is false, disabling
110*0Sstevel@tonic-gate  * these hotkeys.
111*0Sstevel@tonic-gate  */
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate #if	defined(DEBUG) || defined(lint)
114*0Sstevel@tonic-gate #define	KD_DEBUG
115*0Sstevel@tonic-gate #endif
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate #ifdef	KD_DEBUG
118*0Sstevel@tonic-gate boolean_t	kb8042_enable_debug_hotkey = B_FALSE;
119*0Sstevel@tonic-gate boolean_t	kb8042_debug = B_FALSE;
120*0Sstevel@tonic-gate boolean_t	kb8042_getchar_debug = B_FALSE;
121*0Sstevel@tonic-gate boolean_t	kb8042_low_level_debug = B_FALSE;
122*0Sstevel@tonic-gate boolean_t	kb8042_pressrelease_debug = B_FALSE;
123*0Sstevel@tonic-gate static void kb8042_debug_hotkey(int scancode);
124*0Sstevel@tonic-gate #endif
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate enum state_return { STATE_NORMAL, STATE_INTERNAL };
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate static void kb8042_init(struct kb8042 *kb8042);
129*0Sstevel@tonic-gate static uint_t kb8042_intr(caddr_t arg);
130*0Sstevel@tonic-gate static void kb8042_wait_poweron(struct kb8042 *kb8042);
131*0Sstevel@tonic-gate static void kb8042_start_state_machine(struct kb8042 *, boolean_t);
132*0Sstevel@tonic-gate static enum state_return kb8042_state_machine(struct kb8042 *, int, boolean_t);
133*0Sstevel@tonic-gate static void kb8042_send_to_keyboard(struct kb8042 *, int, boolean_t);
134*0Sstevel@tonic-gate static int kb8042_xlate_leds(int);
135*0Sstevel@tonic-gate static void kb8042_streams_setled(struct kbtrans_hardware *hw, int led_state);
136*0Sstevel@tonic-gate static void kb8042_polled_setled(struct kbtrans_hardware *hw, int led_state);
137*0Sstevel@tonic-gate static boolean_t kb8042_polled_keycheck(
138*0Sstevel@tonic-gate 			struct kbtrans_hardware *hw, int *key,
139*0Sstevel@tonic-gate 			enum keystate *state);
140*0Sstevel@tonic-gate static void kb8042_get_initial_leds(struct kb8042 *, int *, int *);
141*0Sstevel@tonic-gate static boolean_t kb8042_autorepeat_detect(struct kb8042 *kb8042, int key_pos,
142*0Sstevel@tonic-gate 			enum keystate state);
143*0Sstevel@tonic-gate static void kb8042_type4_cmd(struct kb8042 *kb8042, int cmd);
144*0Sstevel@tonic-gate static void kb8042_ioctlmsg(struct kb8042 *kb8042, queue_t *, mblk_t *);
145*0Sstevel@tonic-gate static void kb8042_iocdatamsg(queue_t *, mblk_t *);
146*0Sstevel@tonic-gate static void kb8042_process_key(struct kb8042 *, kbtrans_key_t, enum keystate);
147*0Sstevel@tonic-gate static int kb8042_polled_ischar(struct cons_polledio_arg *arg);
148*0Sstevel@tonic-gate static int kb8042_polled_getchar(struct cons_polledio_arg *arg);
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate static struct kbtrans_callbacks kb8042_callbacks = {
151*0Sstevel@tonic-gate 	kb8042_streams_setled,
152*0Sstevel@tonic-gate 	kb8042_polled_setled,
153*0Sstevel@tonic-gate 	kb8042_polled_keycheck,
154*0Sstevel@tonic-gate };
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate extern struct keyboard keyindex_pc;
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate #define	DRIVER_NAME(dip) ddi_driver_name(dip)
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate static	char	module_name[] = "kb8042";
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate static int kb8042_open(queue_t *qp, dev_t *devp, int flag, int sflag,
163*0Sstevel@tonic-gate 			cred_t *credp);
164*0Sstevel@tonic-gate static int kb8042_close(queue_t *qp, int flag, cred_t *credp);
165*0Sstevel@tonic-gate static int kb8042_wsrv();
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate struct module_info kb8042_sinfo = {
168*0Sstevel@tonic-gate 	42,		/* Module ID */
169*0Sstevel@tonic-gate 	module_name,
170*0Sstevel@tonic-gate 	0, 32,		/* Minimum and maximum packet sizes */
171*0Sstevel@tonic-gate 	256, 128	/* High and low water marks */
172*0Sstevel@tonic-gate };
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate static struct qinit kb8042_rinit = {
175*0Sstevel@tonic-gate 	NULL, NULL, kb8042_open, kb8042_close, NULL, &kb8042_sinfo, NULL
176*0Sstevel@tonic-gate };
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate static struct qinit kb8042_winit = {
179*0Sstevel@tonic-gate 	putq, kb8042_wsrv, kb8042_open, kb8042_close, NULL, &kb8042_sinfo, NULL
180*0Sstevel@tonic-gate };
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate struct streamtab
183*0Sstevel@tonic-gate 	kb8042_str_info = { &kb8042_rinit, &kb8042_winit, NULL, NULL };
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate struct kb8042	Kdws = {0};
186*0Sstevel@tonic-gate static dev_info_t *kb8042_dip;
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate static int kb8042_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
189*0Sstevel@tonic-gate 		void **result);
190*0Sstevel@tonic-gate static int kb8042_attach(dev_info_t *, ddi_attach_cmd_t);
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate static 	struct cb_ops cb_kb8042_ops = {
193*0Sstevel@tonic-gate 	nulldev,		/* cb_open */
194*0Sstevel@tonic-gate 	nulldev,		/* cb_close */
195*0Sstevel@tonic-gate 	nodev,			/* cb_strategy */
196*0Sstevel@tonic-gate 	nodev,			/* cb_print */
197*0Sstevel@tonic-gate 	nodev,			/* cb_dump */
198*0Sstevel@tonic-gate 	nodev,			/* cb_read */
199*0Sstevel@tonic-gate 	nodev,			/* cb_write */
200*0Sstevel@tonic-gate 	nodev,			/* cb_ioctl */
201*0Sstevel@tonic-gate 	nodev,			/* cb_devmap */
202*0Sstevel@tonic-gate 	nodev,			/* cb_mmap */
203*0Sstevel@tonic-gate 	nodev,			/* cb_segmap */
204*0Sstevel@tonic-gate 	nochpoll,		/* cb_chpoll */
205*0Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
206*0Sstevel@tonic-gate 	&kb8042_str_info,	/* cb_stream */
207*0Sstevel@tonic-gate 	D_MP
208*0Sstevel@tonic-gate };
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate struct dev_ops kb8042_ops = {
211*0Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
212*0Sstevel@tonic-gate 	0,			/* devo_refcnt */
213*0Sstevel@tonic-gate 	kb8042_getinfo,		/* devo_getinfo */
214*0Sstevel@tonic-gate 	nulldev,		/* devo_identify */
215*0Sstevel@tonic-gate 	nulldev,		/* devo_probe */
216*0Sstevel@tonic-gate 	kb8042_attach,		/* devo_attach */
217*0Sstevel@tonic-gate 	nodev,			/* devo_detach */
218*0Sstevel@tonic-gate 	nodev,			/* devo_reset */
219*0Sstevel@tonic-gate 	&cb_kb8042_ops,		/* devo_cb_ops */
220*0Sstevel@tonic-gate 	(struct bus_ops *)NULL	/* devo_bus_ops */
221*0Sstevel@tonic-gate };
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate /*
225*0Sstevel@tonic-gate  * This is the loadable module wrapper.
226*0Sstevel@tonic-gate  */
227*0Sstevel@tonic-gate #include <sys/modctl.h>
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate /*
230*0Sstevel@tonic-gate  * Module linkage information for the kernel.
231*0Sstevel@tonic-gate  */
232*0Sstevel@tonic-gate static struct modldrv modldrv = {
233*0Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a driver */
234*0Sstevel@tonic-gate 	"PS/2 Keyboard %I%, %E%",
235*0Sstevel@tonic-gate 	&kb8042_ops,	/* driver ops */
236*0Sstevel@tonic-gate };
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
239*0Sstevel@tonic-gate 	MODREV_1,
240*0Sstevel@tonic-gate 	(void *) &modldrv,
241*0Sstevel@tonic-gate 	NULL
242*0Sstevel@tonic-gate };
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate int
245*0Sstevel@tonic-gate _init(void)
246*0Sstevel@tonic-gate {
247*0Sstevel@tonic-gate 	int	rv;
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	rv = mod_install(&modlinkage);
250*0Sstevel@tonic-gate 	return (rv);
251*0Sstevel@tonic-gate }
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate int
255*0Sstevel@tonic-gate _fini(void)
256*0Sstevel@tonic-gate {
257*0Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
258*0Sstevel@tonic-gate }
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate int
261*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
262*0Sstevel@tonic-gate {
263*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
264*0Sstevel@tonic-gate }
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate static int
267*0Sstevel@tonic-gate kb8042_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
268*0Sstevel@tonic-gate {
269*0Sstevel@tonic-gate 	int	rc;
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	struct kb8042	*kb8042;
272*0Sstevel@tonic-gate 	static ddi_device_acc_attr_t attr = {
273*0Sstevel@tonic-gate 		DDI_DEVICE_ATTR_V0,
274*0Sstevel@tonic-gate 		DDI_NEVERSWAP_ACC,
275*0Sstevel@tonic-gate 		DDI_STRICTORDER_ACC,
276*0Sstevel@tonic-gate 	};
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	if (cmd != DDI_ATTACH)
279*0Sstevel@tonic-gate 		return (DDI_FAILURE);
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	kb8042 = &Kdws;
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 	KeyboardConvertScan_init(kb8042);
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	kb8042->debugger.mod1 = 58;	/* Left Ctrl */
286*0Sstevel@tonic-gate 	kb8042->debugger.mod2 = 60;	/* Left Alt */
287*0Sstevel@tonic-gate 	kb8042->debugger.trigger = 33;	/* D */
288*0Sstevel@tonic-gate 	kb8042->debugger.mod1_down = B_FALSE;
289*0Sstevel@tonic-gate 	kb8042->debugger.mod2_down = B_FALSE;
290*0Sstevel@tonic-gate 	kb8042->debugger.enabled = B_FALSE;
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 	kb8042->polled_synthetic_release_pending = B_FALSE;
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	if (ddi_create_minor_node(devi, module_name, S_IFCHR, 0,
295*0Sstevel@tonic-gate 		    DDI_NT_KEYBOARD, 0) == DDI_FAILURE) {
296*0Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
297*0Sstevel@tonic-gate 		return (-1);
298*0Sstevel@tonic-gate 	}
299*0Sstevel@tonic-gate 	kb8042_dip = devi;
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	rc = ddi_regs_map_setup(devi, 0, (caddr_t *)&kb8042->addr,
302*0Sstevel@tonic-gate 		(offset_t)0, (offset_t)0, &attr, &kb8042->handle);
303*0Sstevel@tonic-gate 	if (rc != DDI_SUCCESS) {
304*0Sstevel@tonic-gate #if	defined(KD_DEBUG)
305*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "kb8042_attach:  can't map registers");
306*0Sstevel@tonic-gate #endif
307*0Sstevel@tonic-gate 		return (rc);
308*0Sstevel@tonic-gate 	}
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	if (ddi_get_iblock_cookie(devi, 0, &kb8042->w_iblock) !=
311*0Sstevel@tonic-gate 		DDI_SUCCESS) {
312*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "kb8042_attach:  Can't get iblock cookie");
313*0Sstevel@tonic-gate 		return (DDI_FAILURE);
314*0Sstevel@tonic-gate 	}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	mutex_init(&kb8042->w_hw_mutex, NULL, MUTEX_DRIVER, kb8042->w_iblock);
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	kb8042_init(kb8042);
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 	/*
321*0Sstevel@tonic-gate 	 * Turn on interrupts...
322*0Sstevel@tonic-gate 	 */
323*0Sstevel@tonic-gate 	if (ddi_add_intr(devi, 0,
324*0Sstevel@tonic-gate 		&kb8042->w_iblock, (ddi_idevice_cookie_t *)NULL,
325*0Sstevel@tonic-gate 		kb8042_intr, (caddr_t)kb8042) != DDI_SUCCESS) {
326*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "kb8042_attach: cannot add interrupt");
327*0Sstevel@tonic-gate 		return (DDI_FAILURE);
328*0Sstevel@tonic-gate 	}
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	ddi_report_dev(devi);
331*0Sstevel@tonic-gate #ifdef	KD_DEBUG
332*0Sstevel@tonic-gate 	cmn_err(CE_CONT, "?%s #%d: version %s\n",
333*0Sstevel@tonic-gate 	    DRIVER_NAME(devi), ddi_get_instance(devi), "%I% (%E%)");
334*0Sstevel@tonic-gate #endif
335*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
336*0Sstevel@tonic-gate }
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate /*ARGSUSED*/
339*0Sstevel@tonic-gate static int
340*0Sstevel@tonic-gate kb8042_getinfo(
341*0Sstevel@tonic-gate     dev_info_t *dip,
342*0Sstevel@tonic-gate     ddi_info_cmd_t infocmd,
343*0Sstevel@tonic-gate     void *arg,
344*0Sstevel@tonic-gate     void **result)
345*0Sstevel@tonic-gate {
346*0Sstevel@tonic-gate 	register int error;
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 	switch (infocmd) {
349*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
350*0Sstevel@tonic-gate 		if (kb8042_dip == NULL) {
351*0Sstevel@tonic-gate 			error = DDI_FAILURE;
352*0Sstevel@tonic-gate 		} else {
353*0Sstevel@tonic-gate 			*result = (void *) kb8042_dip;
354*0Sstevel@tonic-gate 			error = DDI_SUCCESS;
355*0Sstevel@tonic-gate 		}
356*0Sstevel@tonic-gate 		break;
357*0Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
358*0Sstevel@tonic-gate 		*result = (void *)0;
359*0Sstevel@tonic-gate 		error = DDI_SUCCESS;
360*0Sstevel@tonic-gate 		break;
361*0Sstevel@tonic-gate 	default:
362*0Sstevel@tonic-gate 		error = DDI_FAILURE;
363*0Sstevel@tonic-gate 		break;
364*0Sstevel@tonic-gate 	}
365*0Sstevel@tonic-gate 	return (error);
366*0Sstevel@tonic-gate }
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate static void
369*0Sstevel@tonic-gate kb8042_init(struct kb8042 *kb8042)
370*0Sstevel@tonic-gate {
371*0Sstevel@tonic-gate 	if (kb8042->w_init)
372*0Sstevel@tonic-gate 		return;
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 	kb8042->w_kblayout = 0;	/* Default to US */
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	kb8042->w_qp = (queue_t *)NULL;
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	kb8042_wait_poweron(kb8042);
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 	kb8042->kb_old_key_pos = 0;
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate 	kb8042->simulated_kbd_type = KB_PC;
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	/* Set up the command state machine and start it running. */
385*0Sstevel@tonic-gate 	kb8042->leds.commanded = -1;	/* Unknown initial state */
386*0Sstevel@tonic-gate 	kb8042->leds.desired = -1;	/* Unknown initial state */
387*0Sstevel@tonic-gate 	kb8042->command_state = KB_COMMAND_STATE_WAIT;
388*0Sstevel@tonic-gate 	kb8042_send_to_keyboard(kb8042, KB_ENABLE, B_FALSE);
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	kb8042->w_init++;
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	(void) drv_setparm(SYSRINT, 1);	/* reset keyboard interrupts */
393*0Sstevel@tonic-gate }
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate /*ARGSUSED2*/
396*0Sstevel@tonic-gate static int
397*0Sstevel@tonic-gate kb8042_open(queue_t *qp, dev_t *devp, int flag, int sflag, cred_t *credp)
398*0Sstevel@tonic-gate {
399*0Sstevel@tonic-gate 	struct kb8042	*kb8042;
400*0Sstevel@tonic-gate 	int err;
401*0Sstevel@tonic-gate 	int initial_leds;
402*0Sstevel@tonic-gate 	int initial_led_mask;
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	kb8042 = &Kdws;
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 	kb8042->w_dev = *devp;
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	if (qp->q_ptr) {
409*0Sstevel@tonic-gate 		return (0);
410*0Sstevel@tonic-gate 	}
411*0Sstevel@tonic-gate 	qp->q_ptr = (caddr_t)kb8042;
412*0Sstevel@tonic-gate 	WR(qp)->q_ptr = qp->q_ptr;
413*0Sstevel@tonic-gate 	if (!kb8042->w_qp)
414*0Sstevel@tonic-gate 		kb8042->w_qp = qp;
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 	kb8042_get_initial_leds(kb8042, &initial_leds, &initial_led_mask);
417*0Sstevel@tonic-gate 	err = kbtrans_streams_init(qp, sflag, credp,
418*0Sstevel@tonic-gate 		(struct kbtrans_hardware *)kb8042, &kb8042_callbacks,
419*0Sstevel@tonic-gate 		&kb8042->hw_kbtrans,
420*0Sstevel@tonic-gate 		initial_leds, initial_led_mask);
421*0Sstevel@tonic-gate 	if (err != 0)
422*0Sstevel@tonic-gate 		return (err);
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	kbtrans_streams_set_keyboard(kb8042->hw_kbtrans, KB_PC, &keyindex_pc);
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	kb8042->polledio.cons_polledio_version = CONSPOLLEDIO_V1;
427*0Sstevel@tonic-gate 	kb8042->polledio.cons_polledio_argument =
428*0Sstevel@tonic-gate 		(struct cons_polledio_arg *)kb8042;
429*0Sstevel@tonic-gate 	kb8042->polledio.cons_polledio_putchar = NULL;
430*0Sstevel@tonic-gate 	kb8042->polledio.cons_polledio_getchar =
431*0Sstevel@tonic-gate 		(int (*)(struct cons_polledio_arg *))kb8042_polled_getchar;
432*0Sstevel@tonic-gate 	kb8042->polledio.cons_polledio_ischar =
433*0Sstevel@tonic-gate 		(boolean_t (*)(struct cons_polledio_arg *))kb8042_polled_ischar;
434*0Sstevel@tonic-gate 	kb8042->polledio.cons_polledio_enter = NULL;
435*0Sstevel@tonic-gate 	kb8042->polledio.cons_polledio_exit = NULL;
436*0Sstevel@tonic-gate 	kb8042->polledio.cons_polledio_setled =
437*0Sstevel@tonic-gate 		(void (*)(struct cons_polledio_arg *, int))kb8042_polled_setled;
438*0Sstevel@tonic-gate 	kb8042->polledio.cons_polledio_keycheck =
439*0Sstevel@tonic-gate 		(boolean_t (*)(struct cons_polledio_arg *, int *,
440*0Sstevel@tonic-gate 		enum keystate *))kb8042_polled_keycheck;
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	qprocson(qp);
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate 	kbtrans_streams_enable(kb8042->hw_kbtrans);
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 	return (0);
447*0Sstevel@tonic-gate }
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate /*ARGSUSED1*/
450*0Sstevel@tonic-gate static int
451*0Sstevel@tonic-gate kb8042_close(queue_t *qp, int flag, cred_t *credp)
452*0Sstevel@tonic-gate {
453*0Sstevel@tonic-gate 	struct kb8042	*kb8042;
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	kb8042 = (struct kb8042 *)qp->q_ptr;
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 	kb8042->w_qp = (queue_t *)NULL;
458*0Sstevel@tonic-gate 	qprocsoff(qp);
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	return (0);
461*0Sstevel@tonic-gate }
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate static int
464*0Sstevel@tonic-gate kb8042_wsrv(queue_t *qp)
465*0Sstevel@tonic-gate {
466*0Sstevel@tonic-gate 	struct kb8042 *kb8042;
467*0Sstevel@tonic-gate 
468*0Sstevel@tonic-gate 	mblk_t	*mp;
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	kb8042 = (struct kb8042 *)qp->q_ptr;
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	while ((mp = getq(qp))) {
473*0Sstevel@tonic-gate 		switch (kbtrans_streams_message(kb8042->hw_kbtrans, mp)) {
474*0Sstevel@tonic-gate 		case KBTRANS_MESSAGE_HANDLED:
475*0Sstevel@tonic-gate 			continue;
476*0Sstevel@tonic-gate 		case KBTRANS_MESSAGE_NOT_HANDLED:
477*0Sstevel@tonic-gate 			break;
478*0Sstevel@tonic-gate 		}
479*0Sstevel@tonic-gate 		switch (mp->b_datap->db_type) {
480*0Sstevel@tonic-gate 		case M_IOCTL:
481*0Sstevel@tonic-gate 			kb8042_ioctlmsg(kb8042, qp, mp);
482*0Sstevel@tonic-gate 			continue;
483*0Sstevel@tonic-gate 		case M_IOCDATA:
484*0Sstevel@tonic-gate 			kb8042_iocdatamsg(qp, mp);
485*0Sstevel@tonic-gate 			continue;
486*0Sstevel@tonic-gate 		case M_DELAY:
487*0Sstevel@tonic-gate 		case M_STARTI:
488*0Sstevel@tonic-gate 		case M_STOPI:
489*0Sstevel@tonic-gate 		case M_READ:	/* ignore, no buffered data */
490*0Sstevel@tonic-gate 			freemsg(mp);
491*0Sstevel@tonic-gate 			continue;
492*0Sstevel@tonic-gate 		case M_FLUSH:
493*0Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;
494*0Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHR)
495*0Sstevel@tonic-gate 				qreply(qp, mp);
496*0Sstevel@tonic-gate 			else
497*0Sstevel@tonic-gate 				freemsg(mp);
498*0Sstevel@tonic-gate 			continue;
499*0Sstevel@tonic-gate 		default:
500*0Sstevel@tonic-gate 			cmn_err(CE_NOTE, "kb8042_wsrv: bad msg %x",
501*0Sstevel@tonic-gate 						mp->b_datap->db_type);
502*0Sstevel@tonic-gate 			freemsg(mp);
503*0Sstevel@tonic-gate 			continue;
504*0Sstevel@tonic-gate 		}
505*0Sstevel@tonic-gate 	}
506*0Sstevel@tonic-gate 	return (0);
507*0Sstevel@tonic-gate }
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate static void
510*0Sstevel@tonic-gate kb8042_streams_setled(struct kbtrans_hardware *hw, int led_state)
511*0Sstevel@tonic-gate {
512*0Sstevel@tonic-gate 	struct kb8042 *kb8042 = (struct kb8042 *)hw;
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 	kb8042->leds.desired = led_state;
515*0Sstevel@tonic-gate 	mutex_enter(&kb8042->w_hw_mutex);
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 	kb8042_start_state_machine(kb8042, B_FALSE);
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 	mutex_exit(&kb8042->w_hw_mutex);
520*0Sstevel@tonic-gate }
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate static void
523*0Sstevel@tonic-gate kb8042_ioctlmsg(struct kb8042 *kb8042, queue_t *qp, mblk_t *mp)
524*0Sstevel@tonic-gate {
525*0Sstevel@tonic-gate 	struct iocblk	*iocp;
526*0Sstevel@tonic-gate 	mblk_t		*datap;
527*0Sstevel@tonic-gate 	int		error;
528*0Sstevel@tonic-gate 	int		tmp;
529*0Sstevel@tonic-gate 
530*0Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	case CONSOPENPOLLEDIO:
535*0Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (struct cons_polledio *));
536*0Sstevel@tonic-gate 		if (error != 0) {
537*0Sstevel@tonic-gate 			miocnak(qp, mp, 0, error);
538*0Sstevel@tonic-gate 			return;
539*0Sstevel@tonic-gate 		}
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 		/*
542*0Sstevel@tonic-gate 		 * We are given an appropriate-sized data block,
543*0Sstevel@tonic-gate 		 * and return a pointer to our structure in it.
544*0Sstevel@tonic-gate 		 */
545*0Sstevel@tonic-gate 		*(struct cons_polledio **)mp->b_cont->b_rptr =
546*0Sstevel@tonic-gate 		    &kb8042->polledio;
547*0Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
548*0Sstevel@tonic-gate 		iocp->ioc_error = 0;
549*0Sstevel@tonic-gate 		qreply(qp, mp);
550*0Sstevel@tonic-gate 		break;
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate 	case CONSCLOSEPOLLEDIO:
553*0Sstevel@tonic-gate 		miocack(qp, mp, 0, 0);
554*0Sstevel@tonic-gate 		break;
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	case CONSSETABORTENABLE:
557*0Sstevel@tonic-gate 		if (iocp->ioc_count != TRANSPARENT) {
558*0Sstevel@tonic-gate 			miocnak(qp, mp, 0, EINVAL);
559*0Sstevel@tonic-gate 			return;
560*0Sstevel@tonic-gate 		}
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 		kb8042->debugger.enabled = *(intptr_t *)mp->b_cont->b_rptr;
563*0Sstevel@tonic-gate 		miocack(qp, mp, 0, 0);
564*0Sstevel@tonic-gate 		break;
565*0Sstevel@tonic-gate 
566*0Sstevel@tonic-gate 	/*
567*0Sstevel@tonic-gate 	 * Valid only in TR_UNTRANS_MODE mode.
568*0Sstevel@tonic-gate 	 */
569*0Sstevel@tonic-gate 	case CONSSETKBDTYPE:
570*0Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (int));
571*0Sstevel@tonic-gate 		if (error != 0) {
572*0Sstevel@tonic-gate 			miocnak(qp, mp, 0, error);
573*0Sstevel@tonic-gate 			return;
574*0Sstevel@tonic-gate 		}
575*0Sstevel@tonic-gate 		tmp =  *(int *)mp->b_cont->b_rptr;
576*0Sstevel@tonic-gate 		if (tmp != KB_PC && tmp != KB_USB) {
577*0Sstevel@tonic-gate 			miocnak(qp, mp, 0, EINVAL);
578*0Sstevel@tonic-gate 			break;
579*0Sstevel@tonic-gate 		}
580*0Sstevel@tonic-gate 		kb8042->simulated_kbd_type = tmp;
581*0Sstevel@tonic-gate 		miocack(qp, mp, 0, 0);
582*0Sstevel@tonic-gate 		break;
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	case KIOCLAYOUT:
585*0Sstevel@tonic-gate 		if (kb8042->w_kblayout == -1) {
586*0Sstevel@tonic-gate 			miocnak(qp, mp, 0, EINVAL);
587*0Sstevel@tonic-gate 			return;
588*0Sstevel@tonic-gate 		}
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
591*0Sstevel@tonic-gate 			miocnak(qp, mp, 0, ENOMEM);
592*0Sstevel@tonic-gate 			return;
593*0Sstevel@tonic-gate 		}
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 		if (kb8042->simulated_kbd_type == KB_USB)
596*0Sstevel@tonic-gate 			*(int *)datap->b_wptr = KBTRANS_USBKB_DEFAULT_LAYOUT;
597*0Sstevel@tonic-gate 		else
598*0Sstevel@tonic-gate 			*(int *)datap->b_wptr = kb8042->w_kblayout;
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
601*0Sstevel@tonic-gate 		if (mp->b_cont)
602*0Sstevel@tonic-gate 			freemsg(mp->b_cont);
603*0Sstevel@tonic-gate 		mp->b_cont = datap;
604*0Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
605*0Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
606*0Sstevel@tonic-gate 		iocp->ioc_error = 0;
607*0Sstevel@tonic-gate 		qreply(qp, mp);
608*0Sstevel@tonic-gate 		break;
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 	case KIOCSLAYOUT:
611*0Sstevel@tonic-gate 		if (iocp->ioc_count != TRANSPARENT) {
612*0Sstevel@tonic-gate 			miocnak(qp, mp, 0, EINVAL);
613*0Sstevel@tonic-gate 			return;
614*0Sstevel@tonic-gate 		}
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 		kb8042->w_kblayout = *(intptr_t *)mp->b_cont->b_rptr;
617*0Sstevel@tonic-gate 		miocack(qp, mp, 0, 0);
618*0Sstevel@tonic-gate 		break;
619*0Sstevel@tonic-gate 
620*0Sstevel@tonic-gate 	case KIOCCMD:
621*0Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (int));
622*0Sstevel@tonic-gate 		if (error != 0) {
623*0Sstevel@tonic-gate 			miocnak(qp, mp, 0, error);
624*0Sstevel@tonic-gate 			return;
625*0Sstevel@tonic-gate 		}
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 		kb8042_type4_cmd(kb8042, *(int *)mp->b_cont->b_rptr);
628*0Sstevel@tonic-gate 		miocack(qp, mp, 0, 0);
629*0Sstevel@tonic-gate 		break;
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate 	default:
632*0Sstevel@tonic-gate #ifdef DEBUG1
633*0Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!kb8042_ioctlmsg %x", iocp->ioc_cmd);
634*0Sstevel@tonic-gate #endif
635*0Sstevel@tonic-gate 		miocnak(qp, mp, 0, EINVAL);
636*0Sstevel@tonic-gate 		return;
637*0Sstevel@tonic-gate 	}
638*0Sstevel@tonic-gate }
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate /*
641*0Sstevel@tonic-gate  * Process a byte received from the keyboard
642*0Sstevel@tonic-gate  */
643*0Sstevel@tonic-gate static void
644*0Sstevel@tonic-gate kb8042_received_byte(
645*0Sstevel@tonic-gate 	struct kb8042	*kb8042,
646*0Sstevel@tonic-gate 	int		scancode)	/* raw scan code */
647*0Sstevel@tonic-gate {
648*0Sstevel@tonic-gate 	boolean_t	legit;		/* is this a legit key pos'n? */
649*0Sstevel@tonic-gate 	int		key_pos = -1;
650*0Sstevel@tonic-gate 	enum keystate	state;
651*0Sstevel@tonic-gate 	boolean_t	synthetic_release_needed;
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate #ifdef	KD_DEBUG
654*0Sstevel@tonic-gate 	kb8042_debug_hotkey(scancode);
655*0Sstevel@tonic-gate #endif
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	if (!kb8042->w_init)	/* can't do anything anyway */
658*0Sstevel@tonic-gate 		return;
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate 	legit = KeyboardConvertScan(kb8042, scancode, &key_pos, &state,
661*0Sstevel@tonic-gate 		&synthetic_release_needed);
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate 	if (legit == 0) {
664*0Sstevel@tonic-gate 		/* Eaten by translation */
665*0Sstevel@tonic-gate #ifdef	KD_DEBUG
666*0Sstevel@tonic-gate 		if (kb8042_debug)
667*0Sstevel@tonic-gate 			prom_printf("kb8042_intr: 0x%x -> ignored\n", scancode);
668*0Sstevel@tonic-gate #endif
669*0Sstevel@tonic-gate 		return;
670*0Sstevel@tonic-gate 	}
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate #ifdef	KD_DEBUG
673*0Sstevel@tonic-gate 	if (kb8042_debug) {
674*0Sstevel@tonic-gate 		prom_printf("kb8042_intr:  0x%x -> %s %d",
675*0Sstevel@tonic-gate 			scancode,
676*0Sstevel@tonic-gate 			state == KEY_RELEASED ? "released" : "pressed",
677*0Sstevel@tonic-gate 			key_pos);
678*0Sstevel@tonic-gate 	}
679*0Sstevel@tonic-gate #endif
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 	/*
682*0Sstevel@tonic-gate 	 * Don't know if we want this permanently, but it seems interesting
683*0Sstevel@tonic-gate 	 * for the moment.
684*0Sstevel@tonic-gate 	 */
685*0Sstevel@tonic-gate 	if (key_pos == kb8042->debugger.mod1) {
686*0Sstevel@tonic-gate #ifdef	KD_DEBUG
687*0Sstevel@tonic-gate 		if (kb8042_debug)
688*0Sstevel@tonic-gate 			prom_printf(" -> debug mod1");
689*0Sstevel@tonic-gate #endif
690*0Sstevel@tonic-gate 		kb8042->debugger.mod1_down = (state == KEY_PRESSED);
691*0Sstevel@tonic-gate 	}
692*0Sstevel@tonic-gate 	if (key_pos == kb8042->debugger.mod2) {
693*0Sstevel@tonic-gate #ifdef	KD_DEBUG
694*0Sstevel@tonic-gate 		if (kb8042_debug)
695*0Sstevel@tonic-gate 			prom_printf(" -> debug mod2");
696*0Sstevel@tonic-gate #endif
697*0Sstevel@tonic-gate 		kb8042->debugger.mod2_down = (state == KEY_PRESSED);
698*0Sstevel@tonic-gate 	}
699*0Sstevel@tonic-gate 	if (kb8042->debugger.enabled &&
700*0Sstevel@tonic-gate 	    key_pos == kb8042->debugger.trigger &&
701*0Sstevel@tonic-gate 	    kb8042->debugger.mod1_down &&
702*0Sstevel@tonic-gate 	    kb8042->debugger.mod2_down) {
703*0Sstevel@tonic-gate #ifdef	KD_DEBUG
704*0Sstevel@tonic-gate 		if (kb8042_debug)
705*0Sstevel@tonic-gate 			prom_printf(" -> debugger\n");
706*0Sstevel@tonic-gate #endif
707*0Sstevel@tonic-gate 		/*
708*0Sstevel@tonic-gate 		 * Require new presses of the modifiers.
709*0Sstevel@tonic-gate 		 */
710*0Sstevel@tonic-gate 		kb8042->debugger.mod1_down = B_FALSE;
711*0Sstevel@tonic-gate 		kb8042->debugger.mod2_down = B_FALSE;
712*0Sstevel@tonic-gate 		abort_sequence_enter(NULL);
713*0Sstevel@tonic-gate 		return;
714*0Sstevel@tonic-gate 	}
715*0Sstevel@tonic-gate 
716*0Sstevel@tonic-gate 	/*
717*0Sstevel@tonic-gate 	 * If there's no queue above us - as can happen if we've been
718*0Sstevel@tonic-gate 	 * attached but not opened - drop the keystroke.
719*0Sstevel@tonic-gate 	 * Note that we do this here instead of above so that
720*0Sstevel@tonic-gate 	 * Ctrl-Alt-D still works.
721*0Sstevel@tonic-gate 	 */
722*0Sstevel@tonic-gate 	if (kb8042->w_qp == NULL) {
723*0Sstevel@tonic-gate #ifdef	KD_DEBUG
724*0Sstevel@tonic-gate 		if (kb8042_debug)
725*0Sstevel@tonic-gate 			prom_printf(" -> nobody home\n");
726*0Sstevel@tonic-gate #endif
727*0Sstevel@tonic-gate 		return;
728*0Sstevel@tonic-gate 	}
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 	/*
731*0Sstevel@tonic-gate 	 * This is to filter out auto repeat since it can't be
732*0Sstevel@tonic-gate 	 * turned off at the hardware.  (Yeah, yeah, PS/2 keyboards
733*0Sstevel@tonic-gate 	 * can.  Don't know whether they've taken over the world.
734*0Sstevel@tonic-gate 	 * Don't think so.)
735*0Sstevel@tonic-gate 	 */
736*0Sstevel@tonic-gate 	if (kb8042_autorepeat_detect(kb8042, key_pos, state)) {
737*0Sstevel@tonic-gate #ifdef	KD_DEBUG
738*0Sstevel@tonic-gate 		if (kb8042_debug)
739*0Sstevel@tonic-gate 			prom_printf(" -> autorepeat ignored\n");
740*0Sstevel@tonic-gate #endif
741*0Sstevel@tonic-gate 		return;
742*0Sstevel@tonic-gate 	}
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate #ifdef	KD_DEBUG
745*0Sstevel@tonic-gate 	if (kb8042_debug)
746*0Sstevel@tonic-gate 		prom_printf(" -> OK\n");
747*0Sstevel@tonic-gate #endif
748*0Sstevel@tonic-gate 
749*0Sstevel@tonic-gate #if	defined(KD_DEBUG)
750*0Sstevel@tonic-gate 	if (kb8042_pressrelease_debug) {
751*0Sstevel@tonic-gate 		prom_printf(" %s%d ",
752*0Sstevel@tonic-gate 			state == KEY_PRESSED ? "+" : "-",
753*0Sstevel@tonic-gate 			key_pos);
754*0Sstevel@tonic-gate 	}
755*0Sstevel@tonic-gate #endif
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate 		kb8042_process_key(kb8042, key_pos, state);
758*0Sstevel@tonic-gate 
759*0Sstevel@tonic-gate 	/*
760*0Sstevel@tonic-gate 	 * This is a total hack.  For some stupid reason, the two additional
761*0Sstevel@tonic-gate 	 * keys on Korean keyboards (Hangul and Hangul/Hanja) report press
762*0Sstevel@tonic-gate 	 * only.  We synthesize a release immediately.
763*0Sstevel@tonic-gate 	 */
764*0Sstevel@tonic-gate 	if (synthetic_release_needed) {
765*0Sstevel@tonic-gate #if	defined(KD_DEBUG)
766*0Sstevel@tonic-gate 		if (kb8042_debug)
767*0Sstevel@tonic-gate 			prom_printf("synthetic release %d\n", key_pos);
768*0Sstevel@tonic-gate 		if (kb8042_pressrelease_debug)
769*0Sstevel@tonic-gate 			prom_printf(" -%d(s) ", key_pos);
770*0Sstevel@tonic-gate #endif
771*0Sstevel@tonic-gate 		(void) kb8042_autorepeat_detect(kb8042, key_pos, KEY_RELEASED);
772*0Sstevel@tonic-gate 		kb8042_process_key(kb8042, key_pos, state);
773*0Sstevel@tonic-gate 	}
774*0Sstevel@tonic-gate }
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate static void
778*0Sstevel@tonic-gate kb8042_process_key(struct kb8042 *kb8042, kbtrans_key_t key_pos,
779*0Sstevel@tonic-gate     enum keystate state)
780*0Sstevel@tonic-gate {
781*0Sstevel@tonic-gate 	kbtrans_key_t key;
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 	ASSERT(key_pos >= 0 && key_pos <= 255);
784*0Sstevel@tonic-gate 	if (kb8042->simulated_kbd_type == KB_PC) {
785*0Sstevel@tonic-gate 		kbtrans_streams_key(kb8042->hw_kbtrans, key_pos, state);
786*0Sstevel@tonic-gate 	} else if (kb8042->simulated_kbd_type == KB_USB) {
787*0Sstevel@tonic-gate 		key = keytab_pc2usb[key_pos];
788*0Sstevel@tonic-gate 		if (key != 0) {
789*0Sstevel@tonic-gate 			kbtrans_streams_key(kb8042->hw_kbtrans, key, state);
790*0Sstevel@tonic-gate 		}
791*0Sstevel@tonic-gate 	}
792*0Sstevel@tonic-gate }
793*0Sstevel@tonic-gate 
794*0Sstevel@tonic-gate /*
795*0Sstevel@tonic-gate  * Called from interrupt handler when keyboard interrupt occurs.
796*0Sstevel@tonic-gate  */
797*0Sstevel@tonic-gate static uint_t
798*0Sstevel@tonic-gate kb8042_intr(caddr_t arg)
799*0Sstevel@tonic-gate {
800*0Sstevel@tonic-gate 	uchar_t scancode;	/* raw scan code */
801*0Sstevel@tonic-gate 	int rc;
802*0Sstevel@tonic-gate 	struct kb8042 *kb8042 = (struct kb8042 *)arg;
803*0Sstevel@tonic-gate 
804*0Sstevel@tonic-gate 	rc = DDI_INTR_UNCLAIMED;
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	/* don't care if drv_setparm succeeds */
807*0Sstevel@tonic-gate 	(void) drv_setparm(SYSRINT, 1);
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 	while (ddi_get8(kb8042->handle, kb8042->addr + I8042_INT_INPUT_AVAIL)
810*0Sstevel@tonic-gate 	    != 0) {
811*0Sstevel@tonic-gate 		rc = DDI_INTR_CLAIMED;
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate 		scancode = ddi_get8(kb8042->handle,
814*0Sstevel@tonic-gate 			kb8042->addr + I8042_INT_INPUT_DATA);
815*0Sstevel@tonic-gate 
816*0Sstevel@tonic-gate #if	defined(KD_DEBUG)
817*0Sstevel@tonic-gate 		if (kb8042_low_level_debug)
818*0Sstevel@tonic-gate 			prom_printf(" <K:%x ", scancode);
819*0Sstevel@tonic-gate #endif
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 		mutex_enter(&kb8042->w_hw_mutex);
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate 		if (kb8042_state_machine(kb8042, scancode, B_FALSE) !=
824*0Sstevel@tonic-gate 		    STATE_NORMAL) {
825*0Sstevel@tonic-gate 			mutex_exit(&kb8042->w_hw_mutex);
826*0Sstevel@tonic-gate 			continue;
827*0Sstevel@tonic-gate 		}
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 
830*0Sstevel@tonic-gate 		mutex_exit(&kb8042->w_hw_mutex);
831*0Sstevel@tonic-gate 
832*0Sstevel@tonic-gate 		kb8042_received_byte(kb8042, scancode);
833*0Sstevel@tonic-gate 	}
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	return (rc);
836*0Sstevel@tonic-gate }
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate static void
839*0Sstevel@tonic-gate kb8042_iocdatamsg(queue_t *qp, mblk_t *mp)
840*0Sstevel@tonic-gate {
841*0Sstevel@tonic-gate 	struct copyresp	*csp;
842*0Sstevel@tonic-gate 
843*0Sstevel@tonic-gate 	csp = (struct copyresp *)mp->b_rptr;
844*0Sstevel@tonic-gate 	if (csp->cp_rval) {
845*0Sstevel@tonic-gate 		freemsg(mp);
846*0Sstevel@tonic-gate 		return;
847*0Sstevel@tonic-gate 	}
848*0Sstevel@tonic-gate 
849*0Sstevel@tonic-gate 	switch (csp->cp_cmd) {
850*0Sstevel@tonic-gate 	default:
851*0Sstevel@tonic-gate 		miocack(qp, mp, 0, 0);
852*0Sstevel@tonic-gate 		break;
853*0Sstevel@tonic-gate 	}
854*0Sstevel@tonic-gate }
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate static boolean_t
857*0Sstevel@tonic-gate kb8042_polled_keycheck(
858*0Sstevel@tonic-gate     struct kbtrans_hardware *hw,
859*0Sstevel@tonic-gate     int *key,
860*0Sstevel@tonic-gate     enum keystate *state)
861*0Sstevel@tonic-gate {
862*0Sstevel@tonic-gate 	struct kb8042 *kb8042 = (struct kb8042 *)hw;
863*0Sstevel@tonic-gate 	int	scancode;
864*0Sstevel@tonic-gate 	boolean_t	legit;
865*0Sstevel@tonic-gate 	boolean_t	synthetic_release_needed;
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate 	if (kb8042->polled_synthetic_release_pending) {
868*0Sstevel@tonic-gate 		*key = kb8042->polled_synthetic_release_key;
869*0Sstevel@tonic-gate 		*state = KEY_RELEASED;
870*0Sstevel@tonic-gate 		kb8042->polled_synthetic_release_pending = B_FALSE;
871*0Sstevel@tonic-gate #if	defined(KD_DEBUG)
872*0Sstevel@tonic-gate 		if (kb8042_getchar_debug)
873*0Sstevel@tonic-gate 			prom_printf("synthetic release 0x%x\n", *key);
874*0Sstevel@tonic-gate #endif
875*0Sstevel@tonic-gate 		(void) kb8042_autorepeat_detect(kb8042, *key, *state);
876*0Sstevel@tonic-gate 		return (B_TRUE);
877*0Sstevel@tonic-gate 	}
878*0Sstevel@tonic-gate 
879*0Sstevel@tonic-gate 	for (;;) {
880*0Sstevel@tonic-gate 		if (ddi_get8(kb8042->handle,
881*0Sstevel@tonic-gate 		    kb8042->addr + I8042_POLL_INPUT_AVAIL) == 0) {
882*0Sstevel@tonic-gate 			return (B_FALSE);
883*0Sstevel@tonic-gate 		}
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 		scancode = ddi_get8(kb8042->handle,
886*0Sstevel@tonic-gate 				kb8042->addr + I8042_POLL_INPUT_DATA);
887*0Sstevel@tonic-gate 
888*0Sstevel@tonic-gate #if	defined(KD_DEBUG)
889*0Sstevel@tonic-gate 		if (kb8042_low_level_debug)
890*0Sstevel@tonic-gate 			prom_printf(" g<%x ", scancode);
891*0Sstevel@tonic-gate #endif
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate 		if (kb8042_state_machine(kb8042, scancode, B_FALSE) !=
894*0Sstevel@tonic-gate 		    STATE_NORMAL) {
895*0Sstevel@tonic-gate 			continue;
896*0Sstevel@tonic-gate 		}
897*0Sstevel@tonic-gate 
898*0Sstevel@tonic-gate #ifdef	KD_DEBUG
899*0Sstevel@tonic-gate 		kb8042_debug_hotkey(scancode);
900*0Sstevel@tonic-gate 		if (kb8042_getchar_debug)
901*0Sstevel@tonic-gate 			prom_printf("polled 0x%x", scancode);
902*0Sstevel@tonic-gate #endif
903*0Sstevel@tonic-gate 
904*0Sstevel@tonic-gate 		legit = KeyboardConvertScan(kb8042, scancode, key, state,
905*0Sstevel@tonic-gate 			&synthetic_release_needed);
906*0Sstevel@tonic-gate 		if (!legit) {
907*0Sstevel@tonic-gate #ifdef	KD_DEBUG
908*0Sstevel@tonic-gate 			if (kb8042_getchar_debug)
909*0Sstevel@tonic-gate 				prom_printf(" -> ignored\n");
910*0Sstevel@tonic-gate #endif
911*0Sstevel@tonic-gate 			continue;
912*0Sstevel@tonic-gate 		}
913*0Sstevel@tonic-gate #ifdef	KD_DEBUG
914*0Sstevel@tonic-gate 		if (kb8042_getchar_debug) {
915*0Sstevel@tonic-gate 			prom_printf(" -> %s %d\n",
916*0Sstevel@tonic-gate 				*state == KEY_PRESSED ? "pressed" : "released",
917*0Sstevel@tonic-gate 				*key);
918*0Sstevel@tonic-gate 		}
919*0Sstevel@tonic-gate #endif
920*0Sstevel@tonic-gate 		/*
921*0Sstevel@tonic-gate 		 * For the moment at least, we rely on hardware autorepeat
922*0Sstevel@tonic-gate 		 * for polled I/O autorepeat.  However, for coordination
923*0Sstevel@tonic-gate 		 * with the interrupt-driven code, maintain the last key
924*0Sstevel@tonic-gate 		 * pressed.
925*0Sstevel@tonic-gate 		 */
926*0Sstevel@tonic-gate 		(void) kb8042_autorepeat_detect(kb8042, *key, *state);
927*0Sstevel@tonic-gate 
928*0Sstevel@tonic-gate 		/*
929*0Sstevel@tonic-gate 		 * This is a total hack to support two additional keys
930*0Sstevel@tonic-gate 		 * on Korean keyboards.  They report only on press, and
931*0Sstevel@tonic-gate 		 * so we synthesize a release.  Most likely this will
932*0Sstevel@tonic-gate 		 * never be important to polled  I/O, but if I do it
933*0Sstevel@tonic-gate 		 * "right" the first time it _won't_ be an issue.
934*0Sstevel@tonic-gate 		 */
935*0Sstevel@tonic-gate 		if (synthetic_release_needed) {
936*0Sstevel@tonic-gate 			kb8042->polled_synthetic_release_pending = B_TRUE;
937*0Sstevel@tonic-gate 			kb8042->polled_synthetic_release_key = *key;
938*0Sstevel@tonic-gate 		}
939*0Sstevel@tonic-gate 
940*0Sstevel@tonic-gate 		if (kb8042->simulated_kbd_type == KB_USB) {
941*0Sstevel@tonic-gate 			*key = keytab_pc2usb[*key];
942*0Sstevel@tonic-gate 		}
943*0Sstevel@tonic-gate 		return (B_TRUE);
944*0Sstevel@tonic-gate 	}
945*0Sstevel@tonic-gate }
946*0Sstevel@tonic-gate 
947*0Sstevel@tonic-gate static void
948*0Sstevel@tonic-gate kb8042_polled_setled(struct kbtrans_hardware *hw, int led_state)
949*0Sstevel@tonic-gate {
950*0Sstevel@tonic-gate 	struct kb8042 *kb8042 = (struct kb8042 *)hw;
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate 	kb8042->leds.desired = led_state;
953*0Sstevel@tonic-gate 
954*0Sstevel@tonic-gate 	kb8042_start_state_machine(kb8042, B_TRUE);
955*0Sstevel@tonic-gate }
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate static void
958*0Sstevel@tonic-gate kb8042_send_to_keyboard(struct kb8042 *kb8042, int byte, boolean_t polled)
959*0Sstevel@tonic-gate {
960*0Sstevel@tonic-gate 	if (polled) {
961*0Sstevel@tonic-gate 		ddi_put8(kb8042->handle,
962*0Sstevel@tonic-gate 		    kb8042->addr + I8042_POLL_OUTPUT_DATA, byte);
963*0Sstevel@tonic-gate 	} else {
964*0Sstevel@tonic-gate 		ddi_put8(kb8042->handle,
965*0Sstevel@tonic-gate 		    kb8042->addr + I8042_INT_OUTPUT_DATA, byte);
966*0Sstevel@tonic-gate 	}
967*0Sstevel@tonic-gate 
968*0Sstevel@tonic-gate #if	defined(KD_DEBUG)
969*0Sstevel@tonic-gate 	if (kb8042_low_level_debug)
970*0Sstevel@tonic-gate 		prom_printf(" >K:%x ", byte);
971*0Sstevel@tonic-gate #endif
972*0Sstevel@tonic-gate }
973*0Sstevel@tonic-gate 
974*0Sstevel@tonic-gate /*
975*0Sstevel@tonic-gate  * Wait until the keyboard is fully up, maybe.
976*0Sstevel@tonic-gate  * We may be the first person to talk to the keyboard, in which case
977*0Sstevel@tonic-gate  * it's patiently waiting to say "AA" to us to tell us it's up.
978*0Sstevel@tonic-gate  * In theory it sends the AA in 300ms < n < 9s, but it's a pretty
979*0Sstevel@tonic-gate  * good bet that we've already spent that long getting to that point,
980*0Sstevel@tonic-gate  * so we'll only wait long enough for the communications electronics to
981*0Sstevel@tonic-gate  * run.
982*0Sstevel@tonic-gate  */
983*0Sstevel@tonic-gate static void
984*0Sstevel@tonic-gate kb8042_wait_poweron(struct kb8042 *kb8042)
985*0Sstevel@tonic-gate {
986*0Sstevel@tonic-gate 	int cnt;
987*0Sstevel@tonic-gate 	int ready;
988*0Sstevel@tonic-gate 	unsigned char byt;
989*0Sstevel@tonic-gate 
990*0Sstevel@tonic-gate 	/* wait for up to about a quarter-second for response */
991*0Sstevel@tonic-gate 	for (cnt = 0; cnt < 250; cnt++) {
992*0Sstevel@tonic-gate 		ready = ddi_get8(kb8042->handle,
993*0Sstevel@tonic-gate 			kb8042->addr + I8042_INT_INPUT_AVAIL);
994*0Sstevel@tonic-gate 		if (ready != 0)
995*0Sstevel@tonic-gate 			break;
996*0Sstevel@tonic-gate 		drv_usecwait(1000);
997*0Sstevel@tonic-gate 	}
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate 	/*
1000*0Sstevel@tonic-gate 	 * If there's something pending, read and discard it.  If not,
1001*0Sstevel@tonic-gate 	 * assume things are OK anyway - maybe somebody else ate it
1002*0Sstevel@tonic-gate 	 * already.  (On a PC, the BIOS almost certainly did.)
1003*0Sstevel@tonic-gate 	 */
1004*0Sstevel@tonic-gate 	if (ready != 0) {
1005*0Sstevel@tonic-gate 		byt = ddi_get8(kb8042->handle,
1006*0Sstevel@tonic-gate 			kb8042->addr + I8042_INT_INPUT_DATA);
1007*0Sstevel@tonic-gate #if	defined(KD_DEBUG)
1008*0Sstevel@tonic-gate 		if (kb8042_low_level_debug)
1009*0Sstevel@tonic-gate 			prom_printf(" <K:%x ", byt);
1010*0Sstevel@tonic-gate #endif
1011*0Sstevel@tonic-gate 	}
1012*0Sstevel@tonic-gate }
1013*0Sstevel@tonic-gate 
1014*0Sstevel@tonic-gate static void
1015*0Sstevel@tonic-gate kb8042_start_state_machine(struct kb8042 *kb8042, boolean_t polled)
1016*0Sstevel@tonic-gate {
1017*0Sstevel@tonic-gate 	if (kb8042->command_state == KB_COMMAND_STATE_IDLE) {
1018*0Sstevel@tonic-gate 		if (kb8042->leds.desired != kb8042->leds.commanded) {
1019*0Sstevel@tonic-gate 			kb8042_send_to_keyboard(kb8042, KB_SET_LED, polled);
1020*0Sstevel@tonic-gate 			kb8042->command_state = KB_COMMAND_STATE_LED;
1021*0Sstevel@tonic-gate 		}
1022*0Sstevel@tonic-gate 	}
1023*0Sstevel@tonic-gate }
1024*0Sstevel@tonic-gate 
1025*0Sstevel@tonic-gate enum state_return
1026*0Sstevel@tonic-gate kb8042_state_machine(struct kb8042 *kb8042, int scancode, boolean_t polled)
1027*0Sstevel@tonic-gate {
1028*0Sstevel@tonic-gate 	switch (kb8042->command_state) {
1029*0Sstevel@tonic-gate 	case KB_COMMAND_STATE_IDLE:
1030*0Sstevel@tonic-gate 		break;
1031*0Sstevel@tonic-gate 
1032*0Sstevel@tonic-gate 	case KB_COMMAND_STATE_LED:
1033*0Sstevel@tonic-gate 		if (scancode == KB_ACK) {
1034*0Sstevel@tonic-gate 			kb8042_send_to_keyboard(kb8042,
1035*0Sstevel@tonic-gate 				kb8042_xlate_leds(kb8042->leds.desired),
1036*0Sstevel@tonic-gate 				polled);
1037*0Sstevel@tonic-gate 			kb8042->leds.commanded = kb8042->leds.desired;
1038*0Sstevel@tonic-gate 			kb8042->command_state = KB_COMMAND_STATE_WAIT;
1039*0Sstevel@tonic-gate 			return (STATE_INTERNAL);
1040*0Sstevel@tonic-gate 		}
1041*0Sstevel@tonic-gate 		/* Drop normal scan codes through. */
1042*0Sstevel@tonic-gate 		break;
1043*0Sstevel@tonic-gate 
1044*0Sstevel@tonic-gate 	case KB_COMMAND_STATE_WAIT:
1045*0Sstevel@tonic-gate 		if (scancode == KB_ACK) {
1046*0Sstevel@tonic-gate 			kb8042->command_state = KB_COMMAND_STATE_IDLE;
1047*0Sstevel@tonic-gate 			kb8042_start_state_machine(kb8042, polled);
1048*0Sstevel@tonic-gate 			return (STATE_INTERNAL);
1049*0Sstevel@tonic-gate 		}
1050*0Sstevel@tonic-gate 		/* Drop normal scan codes through. */
1051*0Sstevel@tonic-gate 		break;
1052*0Sstevel@tonic-gate 	}
1053*0Sstevel@tonic-gate 	return (STATE_NORMAL);
1054*0Sstevel@tonic-gate }
1055*0Sstevel@tonic-gate 
1056*0Sstevel@tonic-gate static int
1057*0Sstevel@tonic-gate kb8042_xlate_leds(int led)
1058*0Sstevel@tonic-gate {
1059*0Sstevel@tonic-gate 	int res;
1060*0Sstevel@tonic-gate 
1061*0Sstevel@tonic-gate 	res = 0;
1062*0Sstevel@tonic-gate 
1063*0Sstevel@tonic-gate 	if (led & LED_NUM_LOCK)
1064*0Sstevel@tonic-gate 		res |= LED_NUM;
1065*0Sstevel@tonic-gate 	if (led & LED_SCROLL_LOCK)
1066*0Sstevel@tonic-gate 		res |= LED_SCR;
1067*0Sstevel@tonic-gate 	if (led & LED_CAPS_LOCK)
1068*0Sstevel@tonic-gate 		res |= LED_CAP;
1069*0Sstevel@tonic-gate 
1070*0Sstevel@tonic-gate 	return (res);
1071*0Sstevel@tonic-gate }
1072*0Sstevel@tonic-gate 
1073*0Sstevel@tonic-gate /*ARGSUSED*/
1074*0Sstevel@tonic-gate static void
1075*0Sstevel@tonic-gate kb8042_get_initial_leds(
1076*0Sstevel@tonic-gate     struct kb8042 *kb8042,
1077*0Sstevel@tonic-gate     int *initial_leds,
1078*0Sstevel@tonic-gate     int *initial_led_mask)
1079*0Sstevel@tonic-gate {
1080*0Sstevel@tonic-gate #if	defined(i86pc)
1081*0Sstevel@tonic-gate 	extern caddr_t	p0_va;
1082*0Sstevel@tonic-gate 	uint8_t		bios_kb_flag;
1083*0Sstevel@tonic-gate 
1084*0Sstevel@tonic-gate 	bios_kb_flag = p0_va[BIOS_KB_FLAG];
1085*0Sstevel@tonic-gate 
1086*0Sstevel@tonic-gate 	*initial_led_mask = LED_CAPS_LOCK | LED_NUM_LOCK | LED_SCROLL_LOCK;
1087*0Sstevel@tonic-gate 	*initial_leds = 0;
1088*0Sstevel@tonic-gate 	if (bios_kb_flag & BIOS_CAPS_STATE)
1089*0Sstevel@tonic-gate 		*initial_leds |= LED_CAPS_LOCK;
1090*0Sstevel@tonic-gate 	if (bios_kb_flag & BIOS_NUM_STATE)
1091*0Sstevel@tonic-gate 		*initial_leds |= LED_NUM_LOCK;
1092*0Sstevel@tonic-gate 	if (bios_kb_flag & BIOS_SCROLL_STATE)
1093*0Sstevel@tonic-gate 		*initial_leds |= LED_SCROLL_LOCK;
1094*0Sstevel@tonic-gate #else
1095*0Sstevel@tonic-gate 	*initial_leds = 0;
1096*0Sstevel@tonic-gate 	*initial_led_mask = 0;
1097*0Sstevel@tonic-gate #endif
1098*0Sstevel@tonic-gate }
1099*0Sstevel@tonic-gate 
1100*0Sstevel@tonic-gate #if	defined(KD_DEBUG)
1101*0Sstevel@tonic-gate static void
1102*0Sstevel@tonic-gate kb8042_debug_hotkey(int scancode)
1103*0Sstevel@tonic-gate {
1104*0Sstevel@tonic-gate 	if (!kb8042_enable_debug_hotkey)
1105*0Sstevel@tonic-gate 		return;
1106*0Sstevel@tonic-gate 
1107*0Sstevel@tonic-gate 	switch (scancode) {
1108*0Sstevel@tonic-gate 	case 0x44:	/* F10 in Scan Set 1 code.  (Set 2 code is 0x09)  */
1109*0Sstevel@tonic-gate 		if (!kb8042_debug) {
1110*0Sstevel@tonic-gate 			prom_printf("\nKeyboard:  normal debugging on\n");
1111*0Sstevel@tonic-gate 			kb8042_debug = B_TRUE;
1112*0Sstevel@tonic-gate 		}
1113*0Sstevel@tonic-gate 		break;
1114*0Sstevel@tonic-gate 	case 0x43:	/* F9 in Scan Set 1 code.  (Set 2 code is 0x01) */
1115*0Sstevel@tonic-gate 		if (!kb8042_getchar_debug) {
1116*0Sstevel@tonic-gate 			prom_printf("\nKeyboard:  getchar debugging on\n");
1117*0Sstevel@tonic-gate 			kb8042_getchar_debug = B_TRUE;
1118*0Sstevel@tonic-gate 		}
1119*0Sstevel@tonic-gate 		break;
1120*0Sstevel@tonic-gate 	case 0x42:	/* F8 in Scan Set 1 code.  (Set 2 code is 0x0a) */
1121*0Sstevel@tonic-gate 		if (!kb8042_low_level_debug) {
1122*0Sstevel@tonic-gate 			prom_printf("\nKeyboard:  low-level debugging on\n");
1123*0Sstevel@tonic-gate 			kb8042_low_level_debug = B_TRUE;
1124*0Sstevel@tonic-gate 		}
1125*0Sstevel@tonic-gate 		break;
1126*0Sstevel@tonic-gate 	case 0x41:	/* F7 in Scan Set 1 code.  (Set 2 code is 0x83) */
1127*0Sstevel@tonic-gate 		if (!kb8042_pressrelease_debug) {
1128*0Sstevel@tonic-gate 			prom_printf(
1129*0Sstevel@tonic-gate 			    "\nKeyboard:  press/release debugging on\n");
1130*0Sstevel@tonic-gate 			kb8042_pressrelease_debug = B_TRUE;
1131*0Sstevel@tonic-gate 		}
1132*0Sstevel@tonic-gate 		break;
1133*0Sstevel@tonic-gate 	case 0x3b:	/* F1 in Scan Set 1 code.  (Set 2 code is 0x05) */
1134*0Sstevel@tonic-gate 		if (kb8042_debug ||
1135*0Sstevel@tonic-gate 		    kb8042_getchar_debug ||
1136*0Sstevel@tonic-gate 		    kb8042_low_level_debug ||
1137*0Sstevel@tonic-gate 		    kb8042_pressrelease_debug) {
1138*0Sstevel@tonic-gate 			prom_printf("\nKeyboard:  all debugging off\n");
1139*0Sstevel@tonic-gate 			kb8042_debug = B_FALSE;
1140*0Sstevel@tonic-gate 			kb8042_getchar_debug = B_FALSE;
1141*0Sstevel@tonic-gate 			kb8042_low_level_debug = B_FALSE;
1142*0Sstevel@tonic-gate 			kb8042_pressrelease_debug = B_FALSE;
1143*0Sstevel@tonic-gate 		}
1144*0Sstevel@tonic-gate 		break;
1145*0Sstevel@tonic-gate 	}
1146*0Sstevel@tonic-gate }
1147*0Sstevel@tonic-gate #endif
1148*0Sstevel@tonic-gate 
1149*0Sstevel@tonic-gate static boolean_t
1150*0Sstevel@tonic-gate kb8042_autorepeat_detect(
1151*0Sstevel@tonic-gate     struct kb8042 *kb8042,
1152*0Sstevel@tonic-gate     int key_pos,
1153*0Sstevel@tonic-gate     enum keystate state)
1154*0Sstevel@tonic-gate {
1155*0Sstevel@tonic-gate 	if (state == KEY_RELEASED) {
1156*0Sstevel@tonic-gate 		if (kb8042->kb_old_key_pos == key_pos)
1157*0Sstevel@tonic-gate 			kb8042->kb_old_key_pos = 0;
1158*0Sstevel@tonic-gate 	} else {
1159*0Sstevel@tonic-gate 		if (kb8042->kb_old_key_pos == key_pos) {
1160*0Sstevel@tonic-gate 			return (B_TRUE);
1161*0Sstevel@tonic-gate 		}
1162*0Sstevel@tonic-gate 		kb8042->kb_old_key_pos = key_pos;
1163*0Sstevel@tonic-gate 	}
1164*0Sstevel@tonic-gate 	return (B_FALSE);
1165*0Sstevel@tonic-gate }
1166*0Sstevel@tonic-gate 
1167*0Sstevel@tonic-gate /* ARGSUSED */
1168*0Sstevel@tonic-gate static void
1169*0Sstevel@tonic-gate kb8042_type4_cmd(struct kb8042 *kb8042, int cmd)
1170*0Sstevel@tonic-gate {
1171*0Sstevel@tonic-gate 	switch (cmd) {
1172*0Sstevel@tonic-gate 	case KBD_CMD_BELL:
1173*0Sstevel@tonic-gate 		beeper_on(BEEP_TYPE4);
1174*0Sstevel@tonic-gate 		break;
1175*0Sstevel@tonic-gate 	case KBD_CMD_NOBELL:
1176*0Sstevel@tonic-gate 		beeper_off();
1177*0Sstevel@tonic-gate 		break;
1178*0Sstevel@tonic-gate 	}
1179*0Sstevel@tonic-gate }
1180*0Sstevel@tonic-gate 
1181*0Sstevel@tonic-gate 
1182*0Sstevel@tonic-gate /*
1183*0Sstevel@tonic-gate  * This is a pass-thru routine to get a character at poll time.
1184*0Sstevel@tonic-gate  */
1185*0Sstevel@tonic-gate static int
1186*0Sstevel@tonic-gate kb8042_polled_getchar(struct cons_polledio_arg *arg)
1187*0Sstevel@tonic-gate {
1188*0Sstevel@tonic-gate 	struct kb8042	*kb8042;
1189*0Sstevel@tonic-gate 
1190*0Sstevel@tonic-gate 	kb8042 = (struct kb8042 *)arg;
1191*0Sstevel@tonic-gate 
1192*0Sstevel@tonic-gate 	return (kbtrans_getchar(kb8042->hw_kbtrans));
1193*0Sstevel@tonic-gate }
1194*0Sstevel@tonic-gate 
1195*0Sstevel@tonic-gate /*
1196*0Sstevel@tonic-gate  * This is a pass-thru routine to get a character at poll time.
1197*0Sstevel@tonic-gate  */
1198*0Sstevel@tonic-gate static int
1199*0Sstevel@tonic-gate kb8042_polled_ischar(struct cons_polledio_arg *arg)
1200*0Sstevel@tonic-gate {
1201*0Sstevel@tonic-gate 	struct kb8042	*kb8042;
1202*0Sstevel@tonic-gate 
1203*0Sstevel@tonic-gate 	kb8042 = (struct kb8042 *)arg;
1204*0Sstevel@tonic-gate 
1205*0Sstevel@tonic-gate 	return (kbtrans_ischar(kb8042->hw_kbtrans));
1206*0Sstevel@tonic-gate }
1207