xref: /onnv-gate/usr/src/uts/common/io/kbd.c (revision 5129:5dc46a0fd425)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53505Sqz150045  * Common Development and Distribution License (the "License").
63505Sqz150045  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
223505Sqz150045  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 						/* SunOS-4.0 1.60	*/
280Sstevel@tonic-gate /*	From:	SunOS4.0	sundev/kbd.c	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * Keyboard input streams module - handles conversion of up/down codes to
320Sstevel@tonic-gate  * ASCII or event format.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate #include <sys/types.h>
350Sstevel@tonic-gate #include <sys/param.h>
360Sstevel@tonic-gate #include <sys/sysmacros.h>
370Sstevel@tonic-gate #include <sys/signal.h>
380Sstevel@tonic-gate #include <sys/termios.h>
390Sstevel@tonic-gate #include <sys/termio.h>
400Sstevel@tonic-gate #include <sys/stream.h>
410Sstevel@tonic-gate #include <sys/stropts.h>
420Sstevel@tonic-gate #include <sys/strsun.h>
430Sstevel@tonic-gate #include <sys/kmem.h>
440Sstevel@tonic-gate #include <sys/file.h>
450Sstevel@tonic-gate #include <sys/uio.h>
460Sstevel@tonic-gate #include <sys/errno.h>
470Sstevel@tonic-gate #include <sys/time.h>
480Sstevel@tonic-gate #include <sys/consdev.h>
490Sstevel@tonic-gate #include <sys/kbd.h>
500Sstevel@tonic-gate #include <sys/kbio.h>
510Sstevel@tonic-gate #include <sys/kbdreg.h>
520Sstevel@tonic-gate #include <sys/vuid_event.h>
530Sstevel@tonic-gate #include <sys/debug.h>
540Sstevel@tonic-gate #include <sys/ddi.h>
550Sstevel@tonic-gate #include <sys/sunddi.h>
560Sstevel@tonic-gate #include <sys/policy.h>
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #include <sys/modctl.h>
59*5129Smarx #include <sys/beep.h>
60*5129Smarx #include <sys/int_limits.h>
610Sstevel@tonic-gate 
620Sstevel@tonic-gate static struct streamtab kbd_info;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate static struct fmodsw fsw = {
650Sstevel@tonic-gate 	"kb",
660Sstevel@tonic-gate 	&kbd_info,
670Sstevel@tonic-gate 	D_MP | D_MTPERMOD
680Sstevel@tonic-gate };
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate  * Module linkage information for the kernel.
720Sstevel@tonic-gate  */
730Sstevel@tonic-gate 
740Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
750Sstevel@tonic-gate 	&mod_strmodops, "streams module for keyboard", &fsw
760Sstevel@tonic-gate };
770Sstevel@tonic-gate 
780Sstevel@tonic-gate static struct modlinkage modlinkage = {
790Sstevel@tonic-gate 	MODREV_1, (void *)&modlstrmod, NULL
800Sstevel@tonic-gate };
810Sstevel@tonic-gate 
820Sstevel@tonic-gate int
_init(void)830Sstevel@tonic-gate _init(void)
840Sstevel@tonic-gate {
850Sstevel@tonic-gate 	return (mod_install(&modlinkage));
860Sstevel@tonic-gate }
870Sstevel@tonic-gate 
880Sstevel@tonic-gate int
_fini(void)890Sstevel@tonic-gate _fini(void)
900Sstevel@tonic-gate {
910Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
920Sstevel@tonic-gate }
930Sstevel@tonic-gate 
940Sstevel@tonic-gate int
_info(struct modinfo * modinfop)950Sstevel@tonic-gate _info(struct modinfo *modinfop)
960Sstevel@tonic-gate {
970Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
980Sstevel@tonic-gate }
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate /*
1010Sstevel@tonic-gate  * For now these are shared.
1020Sstevel@tonic-gate  * These data structures are static (defined in keytables.c) thus
1030Sstevel@tonic-gate  * there is no need to perform any locking.
1040Sstevel@tonic-gate  */
1050Sstevel@tonic-gate extern struct keyboards	keytables[];
1060Sstevel@tonic-gate extern char keystringtab[16][KTAB_STRLEN];
1070Sstevel@tonic-gate extern struct compose_sequence_t kb_compose_table[];
1080Sstevel@tonic-gate extern signed char kb_compose_map[];
1090Sstevel@tonic-gate extern struct fltaccent_sequence_t kb_fltaccent_table[];
1100Sstevel@tonic-gate extern uchar_t kb_numlock_table[];
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate /*
1130Sstevel@tonic-gate  * This value corresponds approximately to max 10 fingers
1140Sstevel@tonic-gate  */
1150Sstevel@tonic-gate static int	kbd_downs_size = 15;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate typedef	struct	key_event {
1180Sstevel@tonic-gate 	uchar_t	key_station;	/* Physical key station associated with event */
1190Sstevel@tonic-gate 	Firm_event event;	/* Event that sent out on down */
1200Sstevel@tonic-gate } Key_event;
1210Sstevel@tonic-gate struct	kbddata {
1220Sstevel@tonic-gate 	queue_t	*kbdd_readq;
1230Sstevel@tonic-gate 	queue_t *kbdd_writeq;
1240Sstevel@tonic-gate 	mblk_t	*kbdd_iocpending;	/* "ioctl" awaiting buffer */
1250Sstevel@tonic-gate 	mblk_t	*kbdd_replypending;	/* "ioctl" reply awaiting result */
1260Sstevel@tonic-gate 	int	kbdd_flags;		/* random flags */
1270Sstevel@tonic-gate 	bufcall_id_t kbdd_bufcallid;	/* bufcall id */
1280Sstevel@tonic-gate 	timeout_id_t kbdd_rptid;	/* timeout id for kbdrpt() */
1290Sstevel@tonic-gate 	timeout_id_t kbdd_layoutid;	/* timeout id for kbdlayout() */
1300Sstevel@tonic-gate 	int	kbdd_iocid;		/* ID of "ioctl" being waited for */
1310Sstevel@tonic-gate 	int	kbdd_iocerror;		/* error return from "ioctl" */
1320Sstevel@tonic-gate 	struct	keyboardstate kbdd_state;
1330Sstevel@tonic-gate 					/*
1340Sstevel@tonic-gate 					 * State of keyboard & keyboard
1350Sstevel@tonic-gate 					 * specific settings, e.g., tables
1360Sstevel@tonic-gate 					 */
1370Sstevel@tonic-gate 	int	kbdd_translate;		/* Translate keycodes? */
1380Sstevel@tonic-gate 	int	kbdd_translatable;	/* Keyboard is translatable? */
1390Sstevel@tonic-gate 	int	kbdd_compat;		/* Generating pre-4.1 events? */
1400Sstevel@tonic-gate 	short	kbdd_ascii_addr;	/* Vuid_id_addr for ascii events */
1410Sstevel@tonic-gate 	short	kbdd_top_addr;		/* Vuid_id_addr for top events */
1420Sstevel@tonic-gate 	short	kbdd_vkey_addr;		/* Vuid_id_addr for vkey events */
1430Sstevel@tonic-gate 	struct	key_event *kbdd_downs;
1440Sstevel@tonic-gate 					/*
1450Sstevel@tonic-gate 					 * Table of key stations currently down
1460Sstevel@tonic-gate 					 * that have firm events that need
1470Sstevel@tonic-gate 					 * to be matched with up transitions
1480Sstevel@tonic-gate 					 * when kbdd_translate is TR_*EVENT
1490Sstevel@tonic-gate 					 */
1500Sstevel@tonic-gate 	int	kbdd_downs_entries; /* # of possible entries in kbdd_downs */
1510Sstevel@tonic-gate 	uint_t	kbdd_downs_bytes; /* # of bytes allocated for kbdd_downs */
1520Sstevel@tonic-gate 	ushort_t compose_key;		/* first compose key */
1530Sstevel@tonic-gate 	ushort_t fltaccent_entry;	/* floating accent keymap entry */
1540Sstevel@tonic-gate 	char	led_state;		/* current state of LEDs */
1553927Sqz150045 	unsigned char shiftkey;		/* used for the new abort keys */
1560Sstevel@tonic-gate };
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate #define	KBD_OPEN	0x00000001 /* keyboard is open for business */
1590Sstevel@tonic-gate #define	KBD_IOCWAIT	0x00000002 /* "open" waiting for "ioctl" to finish */
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate #define	NO_HARD_RESET	0		/* don't do hard reset */
1620Sstevel@tonic-gate #define	HARD_RESET	1		/* do hard reset */
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate  * Constants setup during the first open of a kbd (so that they can be patched
1670Sstevel@tonic-gate  * for debugging purposes).
1680Sstevel@tonic-gate  */
1690Sstevel@tonic-gate static int kbd_repeatrate;
1700Sstevel@tonic-gate static int kbd_repeatdelay;
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate static int kbd_overflow_cnt;	/* Number of times kbd overflowed input q */
1730Sstevel@tonic-gate static int kbd_overflow_msg = 1; /* Whether to print message on q overflow */
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate #ifdef	KBD_DEBUG
1760Sstevel@tonic-gate int	kbd_debug = 0;
1770Sstevel@tonic-gate int	kbd_ra_debug = 0;
1780Sstevel@tonic-gate int	kbd_raw_debug = 0;
1790Sstevel@tonic-gate int	kbd_rpt_debug = 0;
1800Sstevel@tonic-gate int	kbd_input_debug = 0;
1810Sstevel@tonic-gate #endif	/* KBD_DEBUG */
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate static int	kbdopen(queue_t *, dev_t *, int, int, cred_t *);
1840Sstevel@tonic-gate static int	kbdclose(queue_t *, int, cred_t *);
1850Sstevel@tonic-gate static void	kbdwput(queue_t *, mblk_t *);
1860Sstevel@tonic-gate static void	kbdrput(queue_t *, mblk_t *);
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate static struct module_info kbdmiinfo = {
1890Sstevel@tonic-gate 	0,
1900Sstevel@tonic-gate 	"kb",
1910Sstevel@tonic-gate 	0,
1920Sstevel@tonic-gate 	INFPSZ,
1930Sstevel@tonic-gate 	2048,
1940Sstevel@tonic-gate 	128
1950Sstevel@tonic-gate };
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate static struct qinit kbdrinit = {
1980Sstevel@tonic-gate 	(int (*)())kbdrput,
1990Sstevel@tonic-gate 	(int (*)())NULL,
2000Sstevel@tonic-gate 	kbdopen,
2010Sstevel@tonic-gate 	kbdclose,
2020Sstevel@tonic-gate 	(int (*)())NULL,
2030Sstevel@tonic-gate 	&kbdmiinfo
2040Sstevel@tonic-gate };
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate static struct module_info kbdmoinfo = {
2070Sstevel@tonic-gate 	0,
2080Sstevel@tonic-gate 	"kb",
2090Sstevel@tonic-gate 	0,
2100Sstevel@tonic-gate 	INFPSZ,
2110Sstevel@tonic-gate 	2048,
2120Sstevel@tonic-gate 	128
2130Sstevel@tonic-gate };
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate static struct qinit kbdwinit = {
2160Sstevel@tonic-gate 	(int (*)())kbdwput,
2170Sstevel@tonic-gate 	(int (*)())NULL,
2180Sstevel@tonic-gate 	kbdopen,
2190Sstevel@tonic-gate 	kbdclose,
2200Sstevel@tonic-gate 	(int (*)())NULL,
2210Sstevel@tonic-gate 	&kbdmoinfo
2220Sstevel@tonic-gate };
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate static struct streamtab kbd_info = {
2250Sstevel@tonic-gate 	&kbdrinit,
2260Sstevel@tonic-gate 	&kbdwinit,
2270Sstevel@tonic-gate 	NULL,
2280Sstevel@tonic-gate 	NULL,
2290Sstevel@tonic-gate };
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate static void	kbdreioctl(void *);
2320Sstevel@tonic-gate static void	kbdioctl(queue_t *, mblk_t *);
2330Sstevel@tonic-gate static void	kbdflush(struct kbddata *);
2340Sstevel@tonic-gate static void	kbduse(struct kbddata *, unsigned);
2350Sstevel@tonic-gate static void	kbdsetled(struct kbddata *);
236*5129Smarx static void	kbd_beep_off(void *arg);
237*5129Smarx static void	kbd_beep_on(void *arg);
2380Sstevel@tonic-gate static void	kbdcmd(queue_t *, char);
2390Sstevel@tonic-gate static void	kbdreset(struct kbddata *, uint_t);
2400Sstevel@tonic-gate static int	kbdsetkey(struct kbddata *, struct kiockey *,  cred_t *);
2410Sstevel@tonic-gate static int	kbdgetkey(struct kbddata *, struct kiockey *);
2420Sstevel@tonic-gate static int	kbdskey(struct kbddata *, struct kiockeymap *,  cred_t *);
2430Sstevel@tonic-gate static int	kbdgkey(struct kbddata *, struct kiockeymap *);
2440Sstevel@tonic-gate static void	kbdlayouttimeout(void *);
2450Sstevel@tonic-gate static void	kbdinput(struct kbddata *, unsigned);
2460Sstevel@tonic-gate static void	kbdid(struct kbddata *, int);
2470Sstevel@tonic-gate static struct	keymap *settable(struct kbddata *, uint_t);
2480Sstevel@tonic-gate static void	kbdrpt(void *);
2490Sstevel@tonic-gate static void	kbdcancelrpt(struct kbddata *);
2500Sstevel@tonic-gate static void	kbdtranslate(struct kbddata *, unsigned, queue_t *);
2510Sstevel@tonic-gate static int	kbd_do_compose(ushort_t, ushort_t, ushort_t *);
2520Sstevel@tonic-gate static void	kbd_send_esc_event(char, struct kbddata *);
2530Sstevel@tonic-gate char		*strsetwithdecimal(char *, uint_t, uint_t);
2540Sstevel@tonic-gate static void	kbdkeypressed(struct kbddata *, uchar_t, Firm_event *,
2550Sstevel@tonic-gate 								ushort_t);
2560Sstevel@tonic-gate static void	kbdqueuepress(struct kbddata *, uchar_t, Firm_event *);
2570Sstevel@tonic-gate static void	kbdkeyreleased(struct kbddata *, uchar_t);
2580Sstevel@tonic-gate static void	kbdreleaseall(struct kbddata *);
2590Sstevel@tonic-gate static void	kbdputcode(uint_t, queue_t *);
2600Sstevel@tonic-gate static void	kbdputbuf(char *, queue_t *);
2610Sstevel@tonic-gate static void	kbdqueueevent(struct kbddata *, Firm_event *);
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate  * Dummy qbufcall callback routine used by open and close.
2650Sstevel@tonic-gate  * The framework will wake up qwait_sig when we return from
2660Sstevel@tonic-gate  * this routine (as part of leaving the perimeters.)
2670Sstevel@tonic-gate  * (The framework enters the perimeters before calling the qbufcall() callback
2680Sstevel@tonic-gate  * and leaves the perimeters after the callback routine has executed. The
2690Sstevel@tonic-gate  * framework performs an implicit wakeup of any thread in qwait/qwait_sig
2700Sstevel@tonic-gate  * when it leaves the perimeter. See qwait(9E).)
2710Sstevel@tonic-gate  */
2720Sstevel@tonic-gate /* ARGSUSED */
dummy_callback(void * arg)2730Sstevel@tonic-gate static void dummy_callback(void *arg)
2740Sstevel@tonic-gate {}
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate /*
2780Sstevel@tonic-gate  * Open a keyboard.
2790Sstevel@tonic-gate  * Ttyopen sets line characteristics
2800Sstevel@tonic-gate  */
2810Sstevel@tonic-gate /* ARGSUSED */
2820Sstevel@tonic-gate static int
kbdopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * crp)2830Sstevel@tonic-gate kbdopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
2840Sstevel@tonic-gate {
2850Sstevel@tonic-gate 	register int  error;
2860Sstevel@tonic-gate 	register struct	kbddata *kbdd;
2870Sstevel@tonic-gate 	mblk_t *mp;
2880Sstevel@tonic-gate 	mblk_t *datap;
2890Sstevel@tonic-gate 	register struct iocblk *iocb;
2900Sstevel@tonic-gate 	register struct termios *cb;
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	/* Set these up only once so that they could be changed from adb */
2930Sstevel@tonic-gate 	if (!kbd_repeatrate) {
2940Sstevel@tonic-gate 		kbd_repeatrate = (hz+29)/30;
2950Sstevel@tonic-gate 		kbd_repeatdelay = hz/2;
2960Sstevel@tonic-gate 	}
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	if (q->q_ptr != NULL)
2990Sstevel@tonic-gate 		return (0);		/* already attached */
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	/*
3020Sstevel@tonic-gate 	 * Only allow open requests to succeed for privileged users.  This
3030Sstevel@tonic-gate 	 * necessary to prevent users from pushing the "kb" module again
3040Sstevel@tonic-gate 	 * on the stream associated with /dev/kbd.
3050Sstevel@tonic-gate 	 */
3060Sstevel@tonic-gate 	if (secpolicy_console(crp) != 0) {
3070Sstevel@tonic-gate 		return (EPERM);
3080Sstevel@tonic-gate 	}
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	switch (sflag) {
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	case MODOPEN:
3140Sstevel@tonic-gate 		break;
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	case CLONEOPEN:
3170Sstevel@tonic-gate 		return (EINVAL);	/* No Bozos! */
3180Sstevel@tonic-gate 	}
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	/* allocate keyboard */
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	kbdd = kmem_zalloc(sizeof (struct kbddata), KM_SLEEP);
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	/*
3260Sstevel@tonic-gate 	 * Set up queue pointers, so that the "put" procedure will accept
3270Sstevel@tonic-gate 	 * the reply to the "ioctl" message we send down.
3280Sstevel@tonic-gate 	 */
3290Sstevel@tonic-gate 	q->q_ptr = kbdd;
3300Sstevel@tonic-gate 	WR(q)->q_ptr = kbdd;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	qprocson(q);
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	/*
3350Sstevel@tonic-gate 	 * Setup tty modes.
3360Sstevel@tonic-gate 	 */
3370Sstevel@tonic-gate 	while ((mp = mkiocb(TCSETSF)) == NULL) {
3380Sstevel@tonic-gate 		timeout_id_t id = qbufcall(q, sizeof (struct iocblk), BPRI_HI,
3390Sstevel@tonic-gate 		    dummy_callback, NULL);
3400Sstevel@tonic-gate 		if (!qwait_sig(q)) {
3410Sstevel@tonic-gate 			qunbufcall(q, id);
3420Sstevel@tonic-gate 			kmem_free(kbdd, sizeof (struct kbddata));
3430Sstevel@tonic-gate 			qprocsoff(q);
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 			return (EINTR);
3460Sstevel@tonic-gate 		}
3470Sstevel@tonic-gate 	}
3480Sstevel@tonic-gate 	while ((datap = allocb(sizeof (struct termios), BPRI_HI)) ==
349*5129Smarx 	    NULL) {
3500Sstevel@tonic-gate 		timeout_id_t id = qbufcall(q, sizeof (struct termios), BPRI_HI,
3510Sstevel@tonic-gate 		    dummy_callback, NULL);
3520Sstevel@tonic-gate 		if (!qwait_sig(q)) {
3530Sstevel@tonic-gate 			qunbufcall(q, id);
3540Sstevel@tonic-gate 			freemsg(mp);
3550Sstevel@tonic-gate 			kmem_free(kbdd, sizeof (struct kbddata));
3560Sstevel@tonic-gate 			qprocsoff(q);
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 			return (EINTR);
3590Sstevel@tonic-gate 		}
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	iocb		= (struct iocblk *)mp->b_rptr;
3630Sstevel@tonic-gate 	iocb->ioc_count	= sizeof (struct termios);
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	cb = (struct termios *)datap->b_rptr;
3660Sstevel@tonic-gate 	cb->c_iflag = 0;
3670Sstevel@tonic-gate 	cb->c_oflag = 0;
3680Sstevel@tonic-gate 	cb->c_cflag = CREAD|CS8|B1200;
3690Sstevel@tonic-gate 	cb->c_lflag = 0;
3700Sstevel@tonic-gate 	bzero(cb->c_cc, NCCS);
3710Sstevel@tonic-gate 	datap->b_wptr += sizeof (struct termios);
3720Sstevel@tonic-gate 	mp->b_cont = datap;
3730Sstevel@tonic-gate 	kbdd->kbdd_flags |= KBD_IOCWAIT;	/* indicate that we're */
3740Sstevel@tonic-gate 	kbdd->kbdd_iocid = iocb->ioc_id;	/* waiting for this response */
3750Sstevel@tonic-gate 	putnext(WR(q), mp);
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	/*
3780Sstevel@tonic-gate 	 * Now wait for it.  Let our read queue put routine wake us up
3790Sstevel@tonic-gate 	 * when it arrives.
3800Sstevel@tonic-gate 	 */
3810Sstevel@tonic-gate 	while (kbdd->kbdd_flags & KBD_IOCWAIT) {
3820Sstevel@tonic-gate 		if (!qwait_sig(q)) {
3830Sstevel@tonic-gate 			error = EINTR;
3840Sstevel@tonic-gate 			goto error;
3850Sstevel@tonic-gate 		}
3860Sstevel@tonic-gate 	}
3870Sstevel@tonic-gate 	if ((error = kbdd->kbdd_iocerror) != 0)
3880Sstevel@tonic-gate 		goto error;
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	/*
3910Sstevel@tonic-gate 	 * Set up private data.
3920Sstevel@tonic-gate 	 */
3930Sstevel@tonic-gate 	kbdd->kbdd_readq = q;
3940Sstevel@tonic-gate 	kbdd->kbdd_writeq = WR(q);
3950Sstevel@tonic-gate 	kbdd->kbdd_iocpending = NULL;
3960Sstevel@tonic-gate 	kbdd->kbdd_translatable = TR_CAN;
3970Sstevel@tonic-gate 	kbdd->kbdd_translate = TR_ASCII;
3980Sstevel@tonic-gate 	kbdd->kbdd_compat = 1;
3990Sstevel@tonic-gate 	kbdd->kbdd_ascii_addr = ASCII_FIRST;
4000Sstevel@tonic-gate 	kbdd->kbdd_top_addr = TOP_FIRST;
4010Sstevel@tonic-gate 	kbdd->kbdd_vkey_addr = VKEY_FIRST;
4020Sstevel@tonic-gate 	/* Allocate dynamic memory for downs table */
4030Sstevel@tonic-gate 	kbdd->kbdd_downs_entries = kbd_downs_size;
4040Sstevel@tonic-gate 	kbdd->kbdd_downs_bytes = kbd_downs_size * sizeof (Key_event);
4050Sstevel@tonic-gate 	kbdd->kbdd_downs = kmem_alloc(kbdd->kbdd_downs_bytes, KM_SLEEP);
4060Sstevel@tonic-gate 	kbdd->kbdd_flags = KBD_OPEN;
4070Sstevel@tonic-gate 	kbdd->led_state = 0;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	/*
4100Sstevel@tonic-gate 	 * Reset kbd.
4110Sstevel@tonic-gate 	 */
4120Sstevel@tonic-gate 	kbdreset(kbdd, HARD_RESET);
4130Sstevel@tonic-gate 
414*5129Smarx 	(void) beep_init((void *)WR(q), kbd_beep_on, kbd_beep_off, NULL);
415*5129Smarx 
4160Sstevel@tonic-gate 	return (0);
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate error:
4190Sstevel@tonic-gate 	qprocsoff(q);
4200Sstevel@tonic-gate 	kmem_free(kbdd, sizeof (struct kbddata));
4210Sstevel@tonic-gate 	return (error);
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate /*
4250Sstevel@tonic-gate  * Close a keyboard.
4260Sstevel@tonic-gate  */
4270Sstevel@tonic-gate /* ARGSUSED1 */
4280Sstevel@tonic-gate static int
kbdclose(register queue_t * q,int flag,cred_t * crp)4290Sstevel@tonic-gate kbdclose(register queue_t *q, int flag, cred_t *crp)
4300Sstevel@tonic-gate {
4310Sstevel@tonic-gate 	register struct kbddata *kbdd = (struct kbddata *)q->q_ptr;
4320Sstevel@tonic-gate 	register mblk_t *mp;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	qprocsoff(q);
435*5129Smarx 	(void) beep_fini();
4360Sstevel@tonic-gate 	/*
4370Sstevel@tonic-gate 	 * Since we're about to destroy our private data, turn off
4380Sstevel@tonic-gate 	 * our open flag first, so we don't accept any more input
4390Sstevel@tonic-gate 	 * and try to use that data.
4400Sstevel@tonic-gate 	 */
4410Sstevel@tonic-gate 	kbdd->kbdd_flags = 0;
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	if ((mp = kbdd->kbdd_replypending) != NULL) {
4440Sstevel@tonic-gate 		/*
4450Sstevel@tonic-gate 		 * There was a KIOCLAYOUT pending; presumably, it timed out.
4460Sstevel@tonic-gate 		 * Throw the reply away.
4470Sstevel@tonic-gate 		 */
4480Sstevel@tonic-gate 		kbdd->kbdd_replypending = NULL;
4490Sstevel@tonic-gate 		freemsg(mp);
4500Sstevel@tonic-gate 	}
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	/* clear all timeouts */
4530Sstevel@tonic-gate 	if (kbdd->kbdd_bufcallid)
4540Sstevel@tonic-gate 		qunbufcall(q, kbdd->kbdd_bufcallid);
4550Sstevel@tonic-gate 	if (kbdd->kbdd_rptid)
4560Sstevel@tonic-gate 		(void) quntimeout(q, kbdd->kbdd_rptid);
4570Sstevel@tonic-gate 	if (kbdd->kbdd_layoutid)
4580Sstevel@tonic-gate 		(void) quntimeout(q, kbdd->kbdd_layoutid);
4590Sstevel@tonic-gate 	kmem_free(kbdd->kbdd_downs, kbdd->kbdd_downs_bytes);
4600Sstevel@tonic-gate 	kmem_free(kbdd, sizeof (struct kbddata));
4610Sstevel@tonic-gate 	return (0);
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate /*
4650Sstevel@tonic-gate  * Line discipline output queue put procedure: handles M_IOCTL
4660Sstevel@tonic-gate  * messages.
4670Sstevel@tonic-gate  */
4680Sstevel@tonic-gate static void
kbdwput(register queue_t * q,register mblk_t * mp)4690Sstevel@tonic-gate kbdwput(register queue_t *q, register mblk_t *mp)
4700Sstevel@tonic-gate {
4710Sstevel@tonic-gate 	/*
4720Sstevel@tonic-gate 	 * Process M_FLUSH, and some M_IOCTL, messages here; pass
4730Sstevel@tonic-gate 	 * everything else down.
4740Sstevel@tonic-gate 	 */
4750Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	case M_FLUSH:
4780Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
4790Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
4800Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
4810Sstevel@tonic-gate 			flushq(RD(q), FLUSHDATA);
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	default:
4840Sstevel@tonic-gate 		putnext(q, mp);	/* pass it down the line */
4850Sstevel@tonic-gate 		break;
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	case M_IOCTL:
4880Sstevel@tonic-gate 		kbdioctl(q, mp);
4890Sstevel@tonic-gate 		break;
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate static void
kbdreioctl(void * kbdd_addr)4950Sstevel@tonic-gate kbdreioctl(void *kbdd_addr)
4960Sstevel@tonic-gate {
4970Sstevel@tonic-gate 	struct kbddata *kbdd = kbdd_addr;
4980Sstevel@tonic-gate 	queue_t *q;
4990Sstevel@tonic-gate 	mblk_t *mp;
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	kbdd->kbdd_bufcallid = 0;
5020Sstevel@tonic-gate 	q = kbdd->kbdd_writeq;
5030Sstevel@tonic-gate 	if ((mp = kbdd->kbdd_iocpending) != NULL) {
5040Sstevel@tonic-gate 		kbdd->kbdd_iocpending = NULL;	/* not pending any more */
5050Sstevel@tonic-gate 		kbdioctl(q, mp);
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate static void
kbdioctl(register queue_t * q,register mblk_t * mp)5100Sstevel@tonic-gate kbdioctl(register queue_t *q, register mblk_t *mp)
5110Sstevel@tonic-gate {
5120Sstevel@tonic-gate 	register struct kbddata *kbdd = (struct kbddata *)q->q_ptr;
5130Sstevel@tonic-gate 	register struct iocblk *iocp;
5140Sstevel@tonic-gate 	register short	new_translate;
5150Sstevel@tonic-gate 	register Vuid_addr_probe *addr_probe;
5160Sstevel@tonic-gate 	register short	*addr_ptr;
5170Sstevel@tonic-gate 	mblk_t *datap;
5180Sstevel@tonic-gate 	size_t	ioctlrespsize;
5190Sstevel@tonic-gate 	int	err = 0;
520*5129Smarx 	int	tmp;
521*5129Smarx 	int	cycles;
522*5129Smarx 	int	frequency;
523*5129Smarx 	int	msecs;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	case VUIDSFORMAT:
5300Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
5310Sstevel@tonic-gate 		if (err != 0)
5320Sstevel@tonic-gate 			break;
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 		new_translate = (*(int *)mp->b_cont->b_rptr == VUID_NATIVE) ?
5350Sstevel@tonic-gate 		    TR_ASCII : TR_EVENT;
5360Sstevel@tonic-gate 		if (new_translate == kbdd->kbdd_translate)
5370Sstevel@tonic-gate 			break;
5380Sstevel@tonic-gate 		kbdd->kbdd_translate = new_translate;
5390Sstevel@tonic-gate 		goto output_format_change;
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	case KIOCTRANS:
5420Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
5430Sstevel@tonic-gate 		if (err != 0)
5440Sstevel@tonic-gate 			break;
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 		new_translate = *(int *)mp->b_cont->b_rptr;
5470Sstevel@tonic-gate 		if (new_translate == kbdd->kbdd_translate)
5480Sstevel@tonic-gate 			break;
5490Sstevel@tonic-gate 		kbdd->kbdd_translate = new_translate;
5500Sstevel@tonic-gate 		goto output_format_change;
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	case KIOCCMD:
5530Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
5540Sstevel@tonic-gate 		if (err != 0)
5550Sstevel@tonic-gate 			break;
5560Sstevel@tonic-gate 
557*5129Smarx 		tmp = (char)(*(int *)mp->b_cont->b_rptr);
558*5129Smarx 		if (tmp == KBD_CMD_BELL)
559*5129Smarx 			(void) beeper_on(BEEP_TYPE4);
560*5129Smarx 		else if (tmp == KBD_CMD_NOBELL)
561*5129Smarx 			(void) beeper_off();
562*5129Smarx 		else
563*5129Smarx 			kbdcmd(q, tmp);
564*5129Smarx 		break;
565*5129Smarx 
566*5129Smarx 	case KIOCMKTONE:
567*5129Smarx 		if (iocp->ioc_count != TRANSPARENT) {
568*5129Smarx 			/*
569*5129Smarx 			 * We don't support non-transparent ioctls,
570*5129Smarx 			 * i.e. I_STR ioctls
571*5129Smarx 			 */
572*5129Smarx 			err = EINVAL;
573*5129Smarx 			break;
574*5129Smarx 		}
575*5129Smarx 		tmp = (int)(*(intptr_t *)mp->b_cont->b_rptr);
576*5129Smarx 		cycles = tmp & 0xffff;
577*5129Smarx 		msecs = (tmp >> 16) & 0xffff;
578*5129Smarx 
579*5129Smarx 		if (cycles == 0)
580*5129Smarx 			frequency = UINT16_MAX;
581*5129Smarx 		else if (cycles == UINT16_MAX)
582*5129Smarx 			frequency = 0;
583*5129Smarx 		else {
584*5129Smarx 			frequency = (PIT_HZ + cycles / 2) / cycles;
585*5129Smarx 			if (frequency > UINT16_MAX)
586*5129Smarx 				frequency = UINT16_MAX;
587*5129Smarx 		}
588*5129Smarx 
589*5129Smarx 		err = beep_mktone(frequency, msecs);
5900Sstevel@tonic-gate 		break;
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	case KIOCSLED:
5930Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (uchar_t));
5940Sstevel@tonic-gate 		if (err != 0)
5950Sstevel@tonic-gate 			break;
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 		kbdd->led_state = *(uchar_t *)mp->b_cont->b_rptr;
5980Sstevel@tonic-gate 		kbdsetled(kbdd);
5990Sstevel@tonic-gate 		break;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	case KIOCGLED:
6020Sstevel@tonic-gate 		if ((datap = allocb(sizeof (uchar_t), BPRI_HI)) == NULL) {
6030Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
6040Sstevel@tonic-gate 			goto allocfailure;
6050Sstevel@tonic-gate 		}
6060Sstevel@tonic-gate 		*(uchar_t *)datap->b_wptr = kbdd->led_state;
6070Sstevel@tonic-gate 		datap->b_wptr += sizeof (uchar_t);
6080Sstevel@tonic-gate 		if (mp->b_cont)  /* free msg to prevent memory leak */
6090Sstevel@tonic-gate 			freemsg(mp->b_cont);
6100Sstevel@tonic-gate 		mp->b_cont = datap;
6110Sstevel@tonic-gate 		iocp->ioc_count = sizeof (uchar_t);
6120Sstevel@tonic-gate 		break;
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	case VUIDGFORMAT:
6150Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
6160Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
6170Sstevel@tonic-gate 			goto allocfailure;
6180Sstevel@tonic-gate 		}
6190Sstevel@tonic-gate 		*(int *)datap->b_wptr =
6200Sstevel@tonic-gate 		    (kbdd->kbdd_translate == TR_EVENT ||
6210Sstevel@tonic-gate 		    kbdd->kbdd_translate == TR_UNTRANS_EVENT) ?
622*5129Smarx 		    VUID_FIRM_EVENT: VUID_NATIVE;
6230Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
6240Sstevel@tonic-gate 		if (mp->b_cont)  /* free msg to prevent memory leak */
6250Sstevel@tonic-gate 			freemsg(mp->b_cont);
6260Sstevel@tonic-gate 		mp->b_cont = datap;
6270Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
6280Sstevel@tonic-gate 		break;
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	case KIOCGTRANS:
6310Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
6320Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
6330Sstevel@tonic-gate 			goto allocfailure;
6340Sstevel@tonic-gate 		}
6350Sstevel@tonic-gate 		*(int *)datap->b_wptr = kbdd->kbdd_translate;
6360Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
6370Sstevel@tonic-gate 		if (mp->b_cont)  /* free msg to prevent memory leak */
6380Sstevel@tonic-gate 			freemsg(mp->b_cont);
6390Sstevel@tonic-gate 		mp->b_cont = datap;
6400Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
6410Sstevel@tonic-gate 		break;
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	case VUIDSADDR:
6440Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (Vuid_addr_probe));
6450Sstevel@tonic-gate 		if (err != 0)
6460Sstevel@tonic-gate 			break;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 		addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
6490Sstevel@tonic-gate 		switch (addr_probe->base) {
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 		case ASCII_FIRST:
6520Sstevel@tonic-gate 			addr_ptr = &kbdd->kbdd_ascii_addr;
6530Sstevel@tonic-gate 			break;
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 		case TOP_FIRST:
6560Sstevel@tonic-gate 			addr_ptr = &kbdd->kbdd_top_addr;
6570Sstevel@tonic-gate 			break;
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 		case VKEY_FIRST:
6600Sstevel@tonic-gate 			addr_ptr = &kbdd->kbdd_vkey_addr;
6610Sstevel@tonic-gate 			break;
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 		default:
6640Sstevel@tonic-gate 			err = ENODEV;
6650Sstevel@tonic-gate 		}
6660Sstevel@tonic-gate 		if ((err == 0) && (*addr_ptr != addr_probe->data.next)) {
6670Sstevel@tonic-gate 			*addr_ptr = addr_probe->data.next;
6680Sstevel@tonic-gate 			goto output_format_change;
6690Sstevel@tonic-gate 		}
6700Sstevel@tonic-gate 		break;
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	case VUIDGADDR:
6730Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (Vuid_addr_probe));
6740Sstevel@tonic-gate 		if (err != 0)
6750Sstevel@tonic-gate 			break;
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 		addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
6780Sstevel@tonic-gate 		switch (addr_probe->base) {
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 		case ASCII_FIRST:
6810Sstevel@tonic-gate 			addr_probe->data.current = kbdd->kbdd_ascii_addr;
6820Sstevel@tonic-gate 			break;
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 		case TOP_FIRST:
6850Sstevel@tonic-gate 			addr_probe->data.current = kbdd->kbdd_top_addr;
6860Sstevel@tonic-gate 			break;
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 		case VKEY_FIRST:
6890Sstevel@tonic-gate 			addr_probe->data.current = kbdd->kbdd_vkey_addr;
6900Sstevel@tonic-gate 			break;
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 		default:
6930Sstevel@tonic-gate 			err = ENODEV;
6940Sstevel@tonic-gate 		}
6950Sstevel@tonic-gate 		break;
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	case KIOCTRANSABLE:
6980Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
6990Sstevel@tonic-gate 		if (err != 0)
7000Sstevel@tonic-gate 			break;
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 		if (kbdd->kbdd_translatable != *(int *)mp->b_cont->b_rptr) {
7030Sstevel@tonic-gate 			kbdd->kbdd_translatable = *(int *)mp->b_cont->b_rptr;
7040Sstevel@tonic-gate 			kbdreset(kbdd, HARD_RESET);
7050Sstevel@tonic-gate 			goto output_format_change;
7060Sstevel@tonic-gate 		}
7070Sstevel@tonic-gate 		break;
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	case KIOCGTRANSABLE:
7100Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
7110Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
7120Sstevel@tonic-gate 			goto allocfailure;
7130Sstevel@tonic-gate 		}
7140Sstevel@tonic-gate 		*(int *)datap->b_wptr = kbdd->kbdd_translatable;
7150Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
7160Sstevel@tonic-gate 		if (mp->b_cont)  /* free msg to prevent memory leak */
7170Sstevel@tonic-gate 			freemsg(mp->b_cont);
7180Sstevel@tonic-gate 		mp->b_cont = datap;
7190Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
7200Sstevel@tonic-gate 		break;
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	case KIOCSCOMPAT:
7230Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
7240Sstevel@tonic-gate 		if (err != 0)
7250Sstevel@tonic-gate 			break;
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 		kbdd->kbdd_compat = *(int *)mp->b_cont->b_rptr;
7280Sstevel@tonic-gate 		break;
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	case KIOCGCOMPAT:
7310Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
7320Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
7330Sstevel@tonic-gate 			goto allocfailure;
7340Sstevel@tonic-gate 		}
7350Sstevel@tonic-gate 		*(int *)datap->b_wptr = kbdd->kbdd_compat;
7360Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
7370Sstevel@tonic-gate 		if (mp->b_cont)  /* free msg to prevent memory leak */
7380Sstevel@tonic-gate 			freemsg(mp->b_cont);
7390Sstevel@tonic-gate 		mp->b_cont = datap;
7400Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
7410Sstevel@tonic-gate 		break;
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	case KIOCSETKEY:
7440Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (struct kiockey));
7450Sstevel@tonic-gate 		if (err != 0)
7460Sstevel@tonic-gate 			break;
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 		err = kbdsetkey(kbdd, (struct kiockey *)mp->b_cont->b_rptr,
7490Sstevel@tonic-gate 		    iocp->ioc_cr);
7500Sstevel@tonic-gate 		/*
7510Sstevel@tonic-gate 		 * Since this only affects any subsequent key presses,
7520Sstevel@tonic-gate 		 * don't goto output_format_change.  One might want to
7530Sstevel@tonic-gate 		 * toggle the keytable entries dynamically.
7540Sstevel@tonic-gate 		 */
7550Sstevel@tonic-gate 		break;
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	case KIOCGETKEY:
7580Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (struct kiockey));
7590Sstevel@tonic-gate 		if (err != 0)
7600Sstevel@tonic-gate 			break;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 		err = kbdgetkey(kbdd, (struct kiockey *)mp->b_cont->b_rptr);
7630Sstevel@tonic-gate 		break;
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	case KIOCSKEY:
7660Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (struct kiockeymap));
7670Sstevel@tonic-gate 		if (err != 0)
7680Sstevel@tonic-gate 			break;
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 		err = kbdskey(kbdd, (struct kiockeymap *)mp->b_cont->b_rptr,
7710Sstevel@tonic-gate 		    iocp->ioc_cr);
7720Sstevel@tonic-gate 		/*
7730Sstevel@tonic-gate 		 * Since this only affects any subsequent key presses,
7740Sstevel@tonic-gate 		 * don't goto output_format_change.  One might want to
7750Sstevel@tonic-gate 		 * toggle the keytable entries dynamically.
7760Sstevel@tonic-gate 		 */
7770Sstevel@tonic-gate 		break;
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	case KIOCGKEY:
7800Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (struct kiockeymap));
7810Sstevel@tonic-gate 		if (err != 0)
7820Sstevel@tonic-gate 			break;
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 		err = kbdgkey(kbdd, (struct kiockeymap *)mp->b_cont->b_rptr);
7850Sstevel@tonic-gate 		break;
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	case KIOCSDIRECT:
7880Sstevel@tonic-gate 		goto output_format_change;
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	case KIOCGDIRECT:
7910Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
7920Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
7930Sstevel@tonic-gate 			goto allocfailure;
7940Sstevel@tonic-gate 		}
7950Sstevel@tonic-gate 		*(int *)datap->b_wptr = 1;	/* always direct */
7960Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
7970Sstevel@tonic-gate 		if (mp->b_cont) /* free msg to prevent memory leak */
7980Sstevel@tonic-gate 			freemsg(mp->b_cont);
7990Sstevel@tonic-gate 		mp->b_cont = datap;
8000Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
8010Sstevel@tonic-gate 		break;
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	case KIOCTYPE:
8040Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
8050Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
8060Sstevel@tonic-gate 			goto allocfailure;
8070Sstevel@tonic-gate 		}
8080Sstevel@tonic-gate 		*(int *)datap->b_wptr = kbdd->kbdd_state.k_id;
8090Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
8100Sstevel@tonic-gate 		if (mp->b_cont) /* free msg to prevent memory leak */
8110Sstevel@tonic-gate 			freemsg(mp->b_cont);
8120Sstevel@tonic-gate 		mp->b_cont = datap;
8130Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
8140Sstevel@tonic-gate 		break;
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	case KIOCLAYOUT:
8170Sstevel@tonic-gate 		if ((datap = kbdd->kbdd_replypending) != NULL) {
8180Sstevel@tonic-gate 			/*
8190Sstevel@tonic-gate 			 * There was an earlier KIOCLAYOUT pending; presumably,
8200Sstevel@tonic-gate 			 * it timed out.  Throw the reply away.
8210Sstevel@tonic-gate 			 */
8220Sstevel@tonic-gate 			kbdd->kbdd_replypending = NULL;
8230Sstevel@tonic-gate 			freemsg(datap);
8240Sstevel@tonic-gate 		}
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 		if (kbdd->kbdd_state.k_id == KB_SUN4 ||
8270Sstevel@tonic-gate 		    kbdd->kbdd_state.k_id == KB_PC) {
8280Sstevel@tonic-gate 			if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
8290Sstevel@tonic-gate 				ioctlrespsize = sizeof (int);
8300Sstevel@tonic-gate 				goto allocfailure;
8310Sstevel@tonic-gate 			}
8320Sstevel@tonic-gate 			iocp->ioc_rval = 0;
8330Sstevel@tonic-gate 			iocp->ioc_error = 0;	/* brain rot */
8340Sstevel@tonic-gate 			iocp->ioc_count = sizeof (int);
8350Sstevel@tonic-gate 			if (mp->b_cont)   /* free msg to prevent memory leak */
8360Sstevel@tonic-gate 				freemsg(mp->b_cont);
8370Sstevel@tonic-gate 			mp->b_cont = datap;
8380Sstevel@tonic-gate 			mp->b_datap->db_type = M_IOCACK;
8390Sstevel@tonic-gate 			kbdd->kbdd_replypending = mp;
8400Sstevel@tonic-gate 			kbdcmd(q, (char)KBD_CMD_GETLAYOUT);
8410Sstevel@tonic-gate 			if (kbdd->kbdd_layoutid)
8420Sstevel@tonic-gate 				(void) quntimeout(q, kbdd->kbdd_layoutid);
8430Sstevel@tonic-gate 			kbdd->kbdd_layoutid = qtimeout(q, kbdlayouttimeout,
8440Sstevel@tonic-gate 			    kbdd, hz / 5);
8450Sstevel@tonic-gate 			return;		/* wait for reply from keyboard */
8460Sstevel@tonic-gate 		} else {
8470Sstevel@tonic-gate 			/*
8480Sstevel@tonic-gate 			 * Not a Type 4 keyboard; return an immediate error.
8490Sstevel@tonic-gate 			 */
8500Sstevel@tonic-gate 			err = EINVAL;
8510Sstevel@tonic-gate 			break;
8520Sstevel@tonic-gate 		}
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	case KIOCGRPTDELAY:
8550Sstevel@tonic-gate 		/*
8560Sstevel@tonic-gate 		 * Report the autorepeat delay, unit in millisecond
8570Sstevel@tonic-gate 		 */
8580Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
8590Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
8600Sstevel@tonic-gate 			goto allocfailure;
8610Sstevel@tonic-gate 		}
8620Sstevel@tonic-gate 		*(int *)datap->b_wptr = TICK_TO_MSEC(kbd_repeatdelay);
8630Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 		/* free msg to prevent memory leak */
8660Sstevel@tonic-gate 		if (mp->b_cont != NULL)
8670Sstevel@tonic-gate 			freemsg(mp->b_cont);
8680Sstevel@tonic-gate 		mp->b_cont = datap;
8690Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
8700Sstevel@tonic-gate 		break;
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	case KIOCSRPTDELAY:
8730Sstevel@tonic-gate 		/*
8740Sstevel@tonic-gate 		 * Set the autorepeat delay
8750Sstevel@tonic-gate 		 */
8760Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 		if (err != 0)
8790Sstevel@tonic-gate 			break;
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 		/* validate the input */
8820Sstevel@tonic-gate 		if (*(int *)mp->b_cont->b_rptr < KIOCRPTDELAY_MIN) {
8830Sstevel@tonic-gate 			err = EINVAL;
8840Sstevel@tonic-gate 			break;
8850Sstevel@tonic-gate 		}
8860Sstevel@tonic-gate 		kbd_repeatdelay = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
8870Sstevel@tonic-gate 		if (kbd_repeatdelay <= 0)
8880Sstevel@tonic-gate 			kbd_repeatdelay = 1;
8890Sstevel@tonic-gate 		break;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	case KIOCGRPTRATE:
8920Sstevel@tonic-gate 		/*
8930Sstevel@tonic-gate 		 * Report the autorepeat rate
8940Sstevel@tonic-gate 		 */
8950Sstevel@tonic-gate 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
8960Sstevel@tonic-gate 			ioctlrespsize = sizeof (int);
8970Sstevel@tonic-gate 			goto allocfailure;
8980Sstevel@tonic-gate 		}
8990Sstevel@tonic-gate 		*(int *)datap->b_wptr = TICK_TO_MSEC(kbd_repeatrate);
9000Sstevel@tonic-gate 		datap->b_wptr += sizeof (int);
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 		/* free msg to prevent memory leak */
9030Sstevel@tonic-gate 		if (mp->b_cont != NULL)
9040Sstevel@tonic-gate 			freemsg(mp->b_cont);
9050Sstevel@tonic-gate 		mp->b_cont = datap;
9060Sstevel@tonic-gate 		iocp->ioc_count = sizeof (int);
9070Sstevel@tonic-gate 		break;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	case KIOCSRPTRATE:
9100Sstevel@tonic-gate 		/*
9110Sstevel@tonic-gate 		 * Set the autorepeat rate
9120Sstevel@tonic-gate 		 */
9130Sstevel@tonic-gate 		err = miocpullup(mp, sizeof (int));
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 		if (err != 0)
9160Sstevel@tonic-gate 			break;
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 		/* validate the input */
9190Sstevel@tonic-gate 		if (*(int *)mp->b_cont->b_rptr < KIOCRPTRATE_MIN) {
9200Sstevel@tonic-gate 			err = EINVAL;
9210Sstevel@tonic-gate 			break;
9220Sstevel@tonic-gate 		}
9230Sstevel@tonic-gate 		kbd_repeatrate = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
9240Sstevel@tonic-gate 		if (kbd_repeatrate <= 0)
9250Sstevel@tonic-gate 			kbd_repeatrate = 1;
9260Sstevel@tonic-gate 		break;
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	default:
9290Sstevel@tonic-gate 		putnext(q, mp);	/* pass it down the line */
9300Sstevel@tonic-gate 		return;
9310Sstevel@tonic-gate 	}
9320Sstevel@tonic-gate 	goto done;
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate output_format_change:
9350Sstevel@tonic-gate 	kbdflush(kbdd);
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate done:
9380Sstevel@tonic-gate 	if (err != 0) {
9390Sstevel@tonic-gate 		iocp->ioc_rval = 0;
9400Sstevel@tonic-gate 		iocp->ioc_error = err;
9410Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
9420Sstevel@tonic-gate 	} else {
9430Sstevel@tonic-gate 		iocp->ioc_rval = 0;
9440Sstevel@tonic-gate 		iocp->ioc_error = 0;	/* brain rot */
9450Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
9460Sstevel@tonic-gate 	}
9470Sstevel@tonic-gate 	qreply(q, mp);
9480Sstevel@tonic-gate 	return;
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate allocfailure:
9510Sstevel@tonic-gate 	/*
9520Sstevel@tonic-gate 	 * We needed to allocate something to handle this "ioctl", but
9530Sstevel@tonic-gate 	 * couldn't; save this "ioctl" and arrange to get called back when
9540Sstevel@tonic-gate 	 * it's more likely that we can get what we need.
9550Sstevel@tonic-gate 	 * If there's already one being saved, throw it out, since it
9560Sstevel@tonic-gate 	 * must have timed out.
9570Sstevel@tonic-gate 	 */
9580Sstevel@tonic-gate 	if (kbdd->kbdd_iocpending != NULL)
9590Sstevel@tonic-gate 		freemsg(kbdd->kbdd_iocpending);
9600Sstevel@tonic-gate 	kbdd->kbdd_iocpending = mp;
9610Sstevel@tonic-gate 	if (kbdd->kbdd_bufcallid)
9620Sstevel@tonic-gate 		qunbufcall(q, kbdd->kbdd_bufcallid);
9630Sstevel@tonic-gate 	kbdd->kbdd_bufcallid = qbufcall(q, ioctlrespsize, BPRI_HI,
9640Sstevel@tonic-gate 	    kbdreioctl, kbdd);
9650Sstevel@tonic-gate }
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate static void
kbdflush(register struct kbddata * kbdd)9680Sstevel@tonic-gate kbdflush(register struct kbddata *kbdd)
9690Sstevel@tonic-gate {
9700Sstevel@tonic-gate 	register queue_t *q;
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	/* Flush pending data already sent upstream */
9730Sstevel@tonic-gate 	if ((q = kbdd->kbdd_readq) != NULL && q->q_next != NULL)
9740Sstevel@tonic-gate 		(void) putnextctl1(q, M_FLUSH, FLUSHR);
9750Sstevel@tonic-gate 	/* Flush pending ups */
9760Sstevel@tonic-gate 	bzero(kbdd->kbdd_downs, kbdd->kbdd_downs_bytes);
9770Sstevel@tonic-gate 	kbdcancelrpt(kbdd);
9780Sstevel@tonic-gate }
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate /*
9810Sstevel@tonic-gate  * Pass keycode upstream, either translated or untranslated.
9820Sstevel@tonic-gate  */
9830Sstevel@tonic-gate static void
kbduse(register struct kbddata * kbdd,unsigned keycode)9840Sstevel@tonic-gate kbduse(register struct kbddata *kbdd, unsigned keycode)
9850Sstevel@tonic-gate {
9860Sstevel@tonic-gate 	register queue_t *readq;
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate #ifdef	KBD_DEBUG
9890Sstevel@tonic-gate 	if (kbd_input_debug) printf("KBD USE key=%d\n", keycode);
9900Sstevel@tonic-gate #endif
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	if ((readq = kbdd->kbdd_readq) == NULL)
9930Sstevel@tonic-gate 		return;
9940Sstevel@tonic-gate 	if (!kbdd->kbdd_translatable ||
9950Sstevel@tonic-gate 	    kbdd->kbdd_translate == TR_NONE)
9960Sstevel@tonic-gate 		kbdputcode(keycode, readq);
9970Sstevel@tonic-gate 	else
9980Sstevel@tonic-gate 		kbdtranslate(kbdd, keycode, readq);
9990Sstevel@tonic-gate }
10000Sstevel@tonic-gate 
1001*5129Smarx static void
kbd_beep_on(void * arg)1002*5129Smarx kbd_beep_on(void *arg)
1003*5129Smarx {
1004*5129Smarx 	kbdcmd((queue_t *)arg, KBD_CMD_BELL);
1005*5129Smarx }
1006*5129Smarx 
1007*5129Smarx 
1008*5129Smarx static void
kbd_beep_off(void * arg)1009*5129Smarx kbd_beep_off(void *arg)
1010*5129Smarx {
1011*5129Smarx 	kbdcmd((queue_t *)arg, KBD_CMD_NOBELL);
1012*5129Smarx }
1013*5129Smarx 
1014*5129Smarx 
10150Sstevel@tonic-gate /*
10160Sstevel@tonic-gate  * kbdclick is used to remember the current click value of the
10170Sstevel@tonic-gate  * Sun-3 keyboard.  This brain damaged keyboard will reset the
10180Sstevel@tonic-gate  * clicking to the "default" value after a reset command and
10190Sstevel@tonic-gate  * there is no way to read out the current click value.  We
10200Sstevel@tonic-gate  * cannot send a click command immediately after the reset
10210Sstevel@tonic-gate  * command or the keyboard gets screwed up.  So we wait until
10220Sstevel@tonic-gate  * we get the ID byte before we send back the click command.
10230Sstevel@tonic-gate  * Unfortunately, this means that there is a small window
10240Sstevel@tonic-gate  * where the keyboard can click when it really shouldn't be.
10250Sstevel@tonic-gate  * A value of -1 means that kbdclick has not been initialized yet.
10260Sstevel@tonic-gate  */
10270Sstevel@tonic-gate static int kbdclick = -1;
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate /*
10300Sstevel@tonic-gate  * Send command byte to keyboard, if you can.
10310Sstevel@tonic-gate  */
10320Sstevel@tonic-gate static void
kbdcmd(register queue_t * q,char cmd)10330Sstevel@tonic-gate kbdcmd(register queue_t *q, char cmd)
10340Sstevel@tonic-gate {
10350Sstevel@tonic-gate 	register mblk_t *bp;
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	if (canput(q)) {
10380Sstevel@tonic-gate 		if ((bp = allocb(1, BPRI_MED)) == NULL)
10390Sstevel@tonic-gate 			cmn_err(CE_WARN,
1040*5129Smarx 			    "kbdcmd: Can't allocate block for command");
10410Sstevel@tonic-gate 		else {
10420Sstevel@tonic-gate 			*bp->b_wptr++ = cmd;
10430Sstevel@tonic-gate 			putnext(q, bp);
10440Sstevel@tonic-gate 			if (cmd == KBD_CMD_NOCLICK)
10450Sstevel@tonic-gate 				kbdclick = 0;
10460Sstevel@tonic-gate 			else if (cmd == KBD_CMD_CLICK)
10470Sstevel@tonic-gate 				kbdclick = 1;
10480Sstevel@tonic-gate 		}
10490Sstevel@tonic-gate 	}
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate /*
10530Sstevel@tonic-gate  * Update the keyboard LEDs to match the current keyboard state.
10540Sstevel@tonic-gate  * Do this only on Type 4 keyboards; other keyboards don't support the
10550Sstevel@tonic-gate  * KBD_CMD_SETLED command (nor, for that matter, the appropriate LEDs).
10560Sstevel@tonic-gate  */
10570Sstevel@tonic-gate static void
kbdsetled(register struct kbddata * kbdd)10580Sstevel@tonic-gate kbdsetled(register struct kbddata *kbdd)
10590Sstevel@tonic-gate {
10600Sstevel@tonic-gate 	if (kbdd->kbdd_state.k_id == KB_SUN4 ||
10610Sstevel@tonic-gate 	    kbdd->kbdd_state.k_id == KB_PC) {
10620Sstevel@tonic-gate 		kbdcmd(kbdd->kbdd_writeq, KBD_CMD_SETLED);
10630Sstevel@tonic-gate 		kbdcmd(kbdd->kbdd_writeq, kbdd->led_state);
10640Sstevel@tonic-gate 	}
10650Sstevel@tonic-gate }
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate /*
10680Sstevel@tonic-gate  * Reset the keyboard
10690Sstevel@tonic-gate  */
10700Sstevel@tonic-gate static void
kbdreset(register struct kbddata * kbdd,uint_t hard_reset)10710Sstevel@tonic-gate kbdreset(register struct kbddata *kbdd, uint_t hard_reset)
10720Sstevel@tonic-gate {
10730Sstevel@tonic-gate 	register struct keyboardstate *k;
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 	k = &kbdd->kbdd_state;
10760Sstevel@tonic-gate 	if (kbdd->kbdd_translatable) {
10770Sstevel@tonic-gate 		k->k_idstate = KID_NONE;
10780Sstevel@tonic-gate 		k->k_id = -1;
10790Sstevel@tonic-gate 		k->k_state = NORMAL;
10800Sstevel@tonic-gate 		if (hard_reset)
10810Sstevel@tonic-gate 			kbdcmd(kbdd->kbdd_writeq, KBD_CMD_RESET);
10820Sstevel@tonic-gate 	} else {
10830Sstevel@tonic-gate 		bzero(k, sizeof (struct keyboardstate));
10840Sstevel@tonic-gate 		k->k_id = KB_ASCII;
10850Sstevel@tonic-gate 		k->k_idstate = KID_OK;
10860Sstevel@tonic-gate 	}
10870Sstevel@tonic-gate }
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate /*
10900Sstevel@tonic-gate  * Old special codes.
10910Sstevel@tonic-gate  */
10920Sstevel@tonic-gate #define	OLD_SHIFTKEYS	0x80
10930Sstevel@tonic-gate #define	OLD_BUCKYBITS	0x90
10940Sstevel@tonic-gate #define	OLD_FUNNY	0xA0
10950Sstevel@tonic-gate #define	OLD_FA_UMLAUT	0xA9
10960Sstevel@tonic-gate #define	OLD_FA_CFLEX	0xAA
10970Sstevel@tonic-gate #define	OLD_FA_TILDE	0xAB
10980Sstevel@tonic-gate #define	OLD_FA_CEDILLA	0xAC
10990Sstevel@tonic-gate #define	OLD_FA_ACUTE	0xAD
11000Sstevel@tonic-gate #define	OLD_FA_GRAVE	0xAE
11010Sstevel@tonic-gate #define	OLD_ISOCHAR	0xAF
11020Sstevel@tonic-gate #define	OLD_STRING	0xB0
11030Sstevel@tonic-gate #define	OLD_LEFTFUNC	0xC0
11040Sstevel@tonic-gate #define	OLD_RIGHTFUNC	0xD0
11050Sstevel@tonic-gate #define	OLD_TOPFUNC	0xE0
11060Sstevel@tonic-gate #define	OLD_BOTTOMFUNC	0xF0
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate /*
11090Sstevel@tonic-gate  * Map old special codes to new ones.
11100Sstevel@tonic-gate  * Indexed by ((old special code) >> 4) & 0x07; add (old special code) & 0x0F.
11110Sstevel@tonic-gate  */
11120Sstevel@tonic-gate static ushort_t	special_old_to_new[] = {
11130Sstevel@tonic-gate 	SHIFTKEYS,
11140Sstevel@tonic-gate 	BUCKYBITS,
11150Sstevel@tonic-gate 	FUNNY,
11160Sstevel@tonic-gate 	STRING,
11170Sstevel@tonic-gate 	LEFTFUNC,
11180Sstevel@tonic-gate 	RIGHTFUNC,
11190Sstevel@tonic-gate 	TOPFUNC,
11200Sstevel@tonic-gate 	BOTTOMFUNC,
11210Sstevel@tonic-gate };
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate /*
11240Sstevel@tonic-gate  * Set individual keystation translation from old-style entry.
11250Sstevel@tonic-gate  * TODO: Have each keyboard own own translation tables.
11260Sstevel@tonic-gate  */
11270Sstevel@tonic-gate static int
kbdsetkey(register struct kbddata * kbdd,struct kiockey * key,cred_t * cr)11280Sstevel@tonic-gate kbdsetkey(register struct kbddata *kbdd, struct kiockey *key, cred_t *cr)
11290Sstevel@tonic-gate {
11300Sstevel@tonic-gate 	int	strtabindex, i;
11310Sstevel@tonic-gate 	struct	keymap *km;
11320Sstevel@tonic-gate 	register int tablemask;
11330Sstevel@tonic-gate 	register ushort_t entry;
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 	if (key->kio_station >= KEYMAP_SIZE)
11360Sstevel@tonic-gate 		return (EINVAL);
11370Sstevel@tonic-gate 	if (kbdd->kbdd_state.k_curkeyboard == NULL)
11380Sstevel@tonic-gate 		return (EINVAL);
11390Sstevel@tonic-gate 	tablemask = key->kio_tablemask;
11400Sstevel@tonic-gate 	if (tablemask == KIOCABORT1) {
11410Sstevel@tonic-gate 		if (secpolicy_console(cr) != 0)
11420Sstevel@tonic-gate 			return (EPERM);
11430Sstevel@tonic-gate 		kbdd->kbdd_state.k_curkeyboard->k_abort1 = key->kio_station;
11440Sstevel@tonic-gate 		return (0);
11450Sstevel@tonic-gate 	}
11460Sstevel@tonic-gate 	if (tablemask == KIOCABORT2) {
11470Sstevel@tonic-gate 		if (secpolicy_console(cr) != 0)
11480Sstevel@tonic-gate 			return (EPERM);
11490Sstevel@tonic-gate 		kbdd->kbdd_state.k_curkeyboard->k_abort2 = key->kio_station;
11500Sstevel@tonic-gate 		return (0);
11510Sstevel@tonic-gate 	}
11520Sstevel@tonic-gate 	if ((tablemask & ALTGRAPHMASK) ||
11530Sstevel@tonic-gate 	    (km = settable(kbdd, (uint_t)tablemask)) == NULL)
11540Sstevel@tonic-gate 		return (EINVAL);
11550Sstevel@tonic-gate 	if (key->kio_entry >= (uchar_t)OLD_STRING &&
11560Sstevel@tonic-gate 	    key->kio_entry <= (uchar_t)(OLD_STRING + 15)) {
11570Sstevel@tonic-gate 		strtabindex = key->kio_entry - OLD_STRING;
11580Sstevel@tonic-gate 		for (i = 0; i < KTAB_STRLEN; i++)
11590Sstevel@tonic-gate 			keystringtab[strtabindex][i] = key->kio_string[i];
11600Sstevel@tonic-gate 		keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
11610Sstevel@tonic-gate 	}
11620Sstevel@tonic-gate 	entry = key->kio_entry;
11630Sstevel@tonic-gate 	/*
11640Sstevel@tonic-gate 	 * There's nothing we need do with OLD_ISOCHAR.
11650Sstevel@tonic-gate 	 */
11660Sstevel@tonic-gate 	if (entry != OLD_ISOCHAR) {
11670Sstevel@tonic-gate 		if (entry & 0x80) {
11680Sstevel@tonic-gate 			if (entry >= OLD_FA_UMLAUT && entry <= OLD_FA_GRAVE)
11690Sstevel@tonic-gate 				entry = FA_CLASS + (entry & 0x0F) - 9;
11700Sstevel@tonic-gate 			else
11710Sstevel@tonic-gate 				entry =
11720Sstevel@tonic-gate 				    special_old_to_new[entry >> 4 & 0x07]
11730Sstevel@tonic-gate 				    + (entry & 0x0F);
11740Sstevel@tonic-gate 		}
11750Sstevel@tonic-gate 	}
11760Sstevel@tonic-gate 	km->keymap[key->kio_station] = entry;
11770Sstevel@tonic-gate 	return (0);
11780Sstevel@tonic-gate }
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate /*
11810Sstevel@tonic-gate  * Map new special codes to old ones.
11820Sstevel@tonic-gate  * Indexed by (new special code) >> 8; add (new special code) & 0xFF.
11830Sstevel@tonic-gate  */
11840Sstevel@tonic-gate static uchar_t	special_new_to_old[] = {
11850Sstevel@tonic-gate 	0,			/* normal */
11860Sstevel@tonic-gate 	OLD_SHIFTKEYS,		/* SHIFTKEYS */
11870Sstevel@tonic-gate 	OLD_BUCKYBITS,		/* BUCKYBITS */
11880Sstevel@tonic-gate 	OLD_FUNNY,		/* FUNNY */
11890Sstevel@tonic-gate 	OLD_FA_UMLAUT,		/* FA_CLASS */
11900Sstevel@tonic-gate 	OLD_STRING,		/* STRING */
11910Sstevel@tonic-gate 	OLD_LEFTFUNC,		/* FUNCKEYS */
11920Sstevel@tonic-gate };
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate /*
11950Sstevel@tonic-gate  * Get individual keystation translation as old-style entry.
11960Sstevel@tonic-gate  */
11970Sstevel@tonic-gate static int
kbdgetkey(register struct kbddata * kbdd,struct kiockey * key)11980Sstevel@tonic-gate kbdgetkey(register struct kbddata *kbdd, struct	kiockey *key)
11990Sstevel@tonic-gate {
12000Sstevel@tonic-gate 	int	strtabindex, i;
12010Sstevel@tonic-gate 	struct	keymap *km;
12020Sstevel@tonic-gate 	register ushort_t entry;
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	if (key->kio_station >= KEYMAP_SIZE)
12050Sstevel@tonic-gate 		return (EINVAL);
12060Sstevel@tonic-gate 	if (kbdd->kbdd_state.k_curkeyboard == NULL)
12070Sstevel@tonic-gate 		return (EINVAL);
12080Sstevel@tonic-gate 	if (key->kio_tablemask == KIOCABORT1) {
12090Sstevel@tonic-gate 		key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort1;
12100Sstevel@tonic-gate 		return (0);
12110Sstevel@tonic-gate 	}
12120Sstevel@tonic-gate 	if (key->kio_tablemask == KIOCABORT2) {
12130Sstevel@tonic-gate 		key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort2;
12140Sstevel@tonic-gate 		return (0);
12150Sstevel@tonic-gate 	}
12160Sstevel@tonic-gate 	if ((km = settable(kbdd, (uint_t)key->kio_tablemask)) == NULL)
12170Sstevel@tonic-gate 		return (EINVAL);
12180Sstevel@tonic-gate 	entry = km->keymap[key->kio_station];
12190Sstevel@tonic-gate 	if (entry & 0xFF00)
12200Sstevel@tonic-gate 		key->kio_entry =
12210Sstevel@tonic-gate 		    special_new_to_old[(ushort_t)(entry & 0xFF00) >> 8]
12220Sstevel@tonic-gate 		    + (entry & 0x00FF);
12230Sstevel@tonic-gate 	else {
12240Sstevel@tonic-gate 		if (entry & 0x80)
12250Sstevel@tonic-gate 			key->kio_entry = (ushort_t)OLD_ISOCHAR;	/* you lose */
12260Sstevel@tonic-gate 		else
12270Sstevel@tonic-gate 			key->kio_entry = (ushort_t)entry;
12280Sstevel@tonic-gate 	}
12290Sstevel@tonic-gate 	if (entry >= STRING && entry <= (uchar_t)(STRING + 15)) {
12300Sstevel@tonic-gate 		strtabindex = entry - STRING;
12310Sstevel@tonic-gate 		for (i = 0; i < KTAB_STRLEN; i++)
12320Sstevel@tonic-gate 			key->kio_string[i] = keystringtab[strtabindex][i];
12330Sstevel@tonic-gate 	}
12340Sstevel@tonic-gate 	return (0);
12350Sstevel@tonic-gate }
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate /*
12380Sstevel@tonic-gate  * Set individual keystation translation from new-style entry.
12390Sstevel@tonic-gate  * TODO: Have each keyboard own own translation tables.
12400Sstevel@tonic-gate  */
12410Sstevel@tonic-gate static int
kbdskey(register struct kbddata * kbdd,struct kiockeymap * key,cred_t * cr)12420Sstevel@tonic-gate kbdskey(register struct kbddata *kbdd, struct kiockeymap *key, cred_t *cr)
12430Sstevel@tonic-gate {
12440Sstevel@tonic-gate 	int	strtabindex, i;
12450Sstevel@tonic-gate 	struct	keymap *km;
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	if (key->kio_station >= KEYMAP_SIZE)
12480Sstevel@tonic-gate 		return (EINVAL);
12490Sstevel@tonic-gate 	if (kbdd->kbdd_state.k_curkeyboard == NULL)
12500Sstevel@tonic-gate 		return (EINVAL);
12510Sstevel@tonic-gate 	if (key->kio_tablemask == KIOCABORT1) {
12520Sstevel@tonic-gate 		if (secpolicy_console(cr) != 0)
12530Sstevel@tonic-gate 			return (EPERM);
12540Sstevel@tonic-gate 		kbdd->kbdd_state.k_curkeyboard->k_abort1 = key->kio_station;
12550Sstevel@tonic-gate 		return (0);
12560Sstevel@tonic-gate 	}
12570Sstevel@tonic-gate 	if (key->kio_tablemask == KIOCABORT2) {
12580Sstevel@tonic-gate 		if (secpolicy_console(cr) != 0)
12590Sstevel@tonic-gate 			return (EPERM);
12600Sstevel@tonic-gate 		kbdd->kbdd_state.k_curkeyboard->k_abort2 = key->kio_station;
12610Sstevel@tonic-gate 		return (0);
12620Sstevel@tonic-gate 	}
12630Sstevel@tonic-gate 	if ((km = settable(kbdd, (uint_t)key->kio_tablemask)) == NULL)
12640Sstevel@tonic-gate 		return (EINVAL);
12650Sstevel@tonic-gate 	if (key->kio_entry >= STRING &&
12660Sstevel@tonic-gate 	    key->kio_entry <= (ushort_t)(STRING + 15)) {
12670Sstevel@tonic-gate 		strtabindex = key->kio_entry-STRING;
12680Sstevel@tonic-gate 		for (i = 0; i < KTAB_STRLEN; i++)
12690Sstevel@tonic-gate 			keystringtab[strtabindex][i] = key->kio_string[i];
12700Sstevel@tonic-gate 		keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
12710Sstevel@tonic-gate 	}
12720Sstevel@tonic-gate 	km->keymap[key->kio_station] = key->kio_entry;
12730Sstevel@tonic-gate 	return (0);
12740Sstevel@tonic-gate }
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate /*
12770Sstevel@tonic-gate  * Get individual keystation translation as new-style entry.
12780Sstevel@tonic-gate  */
12790Sstevel@tonic-gate static int
kbdgkey(register struct kbddata * kbdd,struct kiockeymap * key)12800Sstevel@tonic-gate kbdgkey(register struct kbddata *kbdd, struct	kiockeymap *key)
12810Sstevel@tonic-gate {
12820Sstevel@tonic-gate 	int	strtabindex, i;
12830Sstevel@tonic-gate 	struct	keymap *km;
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 	if (key->kio_station >= KEYMAP_SIZE)
12860Sstevel@tonic-gate 		return (EINVAL);
12870Sstevel@tonic-gate 	if (kbdd->kbdd_state.k_curkeyboard == NULL)
12880Sstevel@tonic-gate 		return (EINVAL);
12890Sstevel@tonic-gate 	if (key->kio_tablemask == KIOCABORT1) {
12900Sstevel@tonic-gate 		key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort1;
12910Sstevel@tonic-gate 		return (0);
12920Sstevel@tonic-gate 	}
12930Sstevel@tonic-gate 	if (key->kio_tablemask == KIOCABORT2) {
12940Sstevel@tonic-gate 		key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort2;
12950Sstevel@tonic-gate 		return (0);
12960Sstevel@tonic-gate 	}
12970Sstevel@tonic-gate 	if ((km = settable(kbdd, (uint_t)key->kio_tablemask)) == NULL)
12980Sstevel@tonic-gate 		return (EINVAL);
12990Sstevel@tonic-gate 	key->kio_entry = km->keymap[key->kio_station];
13000Sstevel@tonic-gate 	if (key->kio_entry >= STRING &&
13010Sstevel@tonic-gate 	    key->kio_entry <= (ushort_t)(STRING + 15)) {
13020Sstevel@tonic-gate 		strtabindex = key->kio_entry-STRING;
13030Sstevel@tonic-gate 		for (i = 0; i < KTAB_STRLEN; i++)
13040Sstevel@tonic-gate 			key->kio_string[i] = keystringtab[strtabindex][i];
13050Sstevel@tonic-gate 	}
13060Sstevel@tonic-gate 	return (0);
13070Sstevel@tonic-gate }
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate static void
kbdlayouttimeout(void * arg)13100Sstevel@tonic-gate kbdlayouttimeout(void *arg)
13110Sstevel@tonic-gate {
13120Sstevel@tonic-gate 	struct kbddata *kbdd = arg;
13130Sstevel@tonic-gate 	mblk_t *mp;
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 	kbdd->kbdd_layoutid = 0;
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	/*
13180Sstevel@tonic-gate 	 * Timed out waiting for reply to "get keyboard layout" command.
13190Sstevel@tonic-gate 	 * Return an ETIME error.
13200Sstevel@tonic-gate 	 */
13210Sstevel@tonic-gate 	if ((mp = kbdd->kbdd_replypending) != NULL) {
13220Sstevel@tonic-gate 		kbdd->kbdd_replypending = NULL;
13230Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCNAK;
13240Sstevel@tonic-gate 		((struct iocblk *)mp->b_rptr)->ioc_error = ETIME;
13250Sstevel@tonic-gate 		putnext(kbdd->kbdd_readq, mp);
13260Sstevel@tonic-gate 	}
13270Sstevel@tonic-gate }
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate /*
13300Sstevel@tonic-gate  * Put procedure for input from driver end of stream (read queue).
13310Sstevel@tonic-gate  */
13320Sstevel@tonic-gate static void
kbdrput(register queue_t * q,register mblk_t * mp)13330Sstevel@tonic-gate kbdrput(register queue_t *q, register mblk_t *mp)
13340Sstevel@tonic-gate {
13350Sstevel@tonic-gate 	struct kbddata *kbdd = (struct kbddata *)q->q_ptr;
13360Sstevel@tonic-gate 	register mblk_t *bp;
13370Sstevel@tonic-gate 	register uchar_t *readp;
13380Sstevel@tonic-gate 	struct iocblk *iocp;
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	if (kbdd == 0) {
13410Sstevel@tonic-gate 		freemsg(mp);	/* nobody's listening */
13420Sstevel@tonic-gate 		return;
13430Sstevel@tonic-gate 	}
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 	case M_FLUSH:
13480Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
13490Sstevel@tonic-gate 			flushq(WR(q), FLUSHDATA);
13500Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR)
13510Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 	default:
13540Sstevel@tonic-gate 		putnext(q, mp);
13550Sstevel@tonic-gate 		return;
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate 	case M_BREAK:
13580Sstevel@tonic-gate 		/*
13590Sstevel@tonic-gate 		 * Will get M_BREAK only if this is not the system
13600Sstevel@tonic-gate 		 * keyboard, otherwise serial port will eat break
13610Sstevel@tonic-gate 		 * and call kmdb/OBP, without passing anything up.
13620Sstevel@tonic-gate 		 */
13630Sstevel@tonic-gate 		freemsg(mp);
13640Sstevel@tonic-gate 		return;
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 	case M_IOCACK:
13670Sstevel@tonic-gate 	case M_IOCNAK:
13680Sstevel@tonic-gate 		/*
13690Sstevel@tonic-gate 		 * If we are doing an "ioctl" ourselves, check if this
13700Sstevel@tonic-gate 		 * is the reply to that code.  If so, wake up the
13710Sstevel@tonic-gate 		 * "open" routine, and toss the reply, otherwise just
13720Sstevel@tonic-gate 		 * pass it up.
13730Sstevel@tonic-gate 		 */
13740Sstevel@tonic-gate 		iocp = (struct iocblk *)mp->b_rptr;
13750Sstevel@tonic-gate 		if (!(kbdd->kbdd_flags & KBD_IOCWAIT) ||
13760Sstevel@tonic-gate 		    iocp->ioc_id != kbdd->kbdd_iocid) {
13770Sstevel@tonic-gate 			/*
13780Sstevel@tonic-gate 			 * This isn't the reply we're looking for.  Move along.
13790Sstevel@tonic-gate 			 */
13800Sstevel@tonic-gate 			if (kbdd->kbdd_flags & KBD_OPEN)
13810Sstevel@tonic-gate 				putnext(q, mp);
13820Sstevel@tonic-gate 			else
13830Sstevel@tonic-gate 				freemsg(mp);	/* not ready to listen */
13840Sstevel@tonic-gate 		} else {
13850Sstevel@tonic-gate 			kbdd->kbdd_flags &= ~KBD_IOCWAIT;
13860Sstevel@tonic-gate 			kbdd->kbdd_iocerror = iocp->ioc_error;
13870Sstevel@tonic-gate 			freemsg(mp);
13880Sstevel@tonic-gate 		}
13890Sstevel@tonic-gate 		return;
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 	case M_DATA:
13920Sstevel@tonic-gate 		if (!(kbdd->kbdd_flags & KBD_OPEN)) {
13930Sstevel@tonic-gate 			freemsg(mp);	/* not read to listen */
13940Sstevel@tonic-gate 			return;
13950Sstevel@tonic-gate 		}
13960Sstevel@tonic-gate 		break;
13970Sstevel@tonic-gate 	}
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 	/*
14000Sstevel@tonic-gate 	 * A data message, consisting of bytes from the keyboard.
14010Sstevel@tonic-gate 	 * Ram them through our state machine.
14020Sstevel@tonic-gate 	 */
14030Sstevel@tonic-gate 	bp = mp;
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 	do {
14060Sstevel@tonic-gate 		readp = bp->b_rptr;
14070Sstevel@tonic-gate 		while (readp < bp->b_wptr)
14080Sstevel@tonic-gate 			kbdinput(kbdd, *readp++);
14090Sstevel@tonic-gate 		bp->b_rptr = readp;
14100Sstevel@tonic-gate 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 	freemsg(mp);
14130Sstevel@tonic-gate }
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate /*
14160Sstevel@tonic-gate  * A keypress was received. Process it through the state machine
14170Sstevel@tonic-gate  * to check for aborts.
14180Sstevel@tonic-gate  */
14190Sstevel@tonic-gate static void
kbdinput(register struct kbddata * kbdd,register unsigned key)14200Sstevel@tonic-gate kbdinput(register struct kbddata *kbdd, register unsigned key)
14210Sstevel@tonic-gate {
14220Sstevel@tonic-gate 	register struct keyboardstate *k;
14230Sstevel@tonic-gate 	register mblk_t *mp;
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate 	k = &kbdd->kbdd_state;
14260Sstevel@tonic-gate #ifdef	KBD_DEBUG
14270Sstevel@tonic-gate 	if (kbd_input_debug)
14280Sstevel@tonic-gate 		printf("kbdinput key %x\n", key);
14290Sstevel@tonic-gate #endif
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	switch (k->k_idstate) {
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	case KID_NONE:
14340Sstevel@tonic-gate 		if (key == RESETKEY) {
14350Sstevel@tonic-gate 			k->k_idstate = KID_GOT_PREFACE;
14360Sstevel@tonic-gate 		} else  {
14370Sstevel@tonic-gate 			kbdreset(kbdd, HARD_RESET);
14380Sstevel@tonic-gate 			/* allows hot plug of kbd after booting without kbd */
14390Sstevel@tonic-gate 		}
14400Sstevel@tonic-gate 		return;
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 	case KID_GOT_PREFACE:
14430Sstevel@tonic-gate 		kbdid(kbdd, (int)key);
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 		/*
14460Sstevel@tonic-gate 		 * We just did a reset command to a Type 3 or Type 4
14470Sstevel@tonic-gate 		 * keyboard which sets the click back to the default
14480Sstevel@tonic-gate 		 * (which is currently ON!).  We use the kbdclick
14490Sstevel@tonic-gate 		 * variable to see if the keyboard should be turned on
14500Sstevel@tonic-gate 		 * or off.  If it has not been set, then we use the
14510Sstevel@tonic-gate 		 * keyboard-click? property.
14520Sstevel@tonic-gate 		 */
14530Sstevel@tonic-gate 		switch (kbdclick) {
14540Sstevel@tonic-gate 		case 0:
14550Sstevel@tonic-gate 			kbdcmd(kbdd->kbdd_writeq, KBD_CMD_NOCLICK);
14560Sstevel@tonic-gate 			break;
14570Sstevel@tonic-gate 		case 1:
14580Sstevel@tonic-gate 			kbdcmd(kbdd->kbdd_writeq, KBD_CMD_CLICK);
14590Sstevel@tonic-gate 			break;
14600Sstevel@tonic-gate 		case -1:
14610Sstevel@tonic-gate 		default:
14620Sstevel@tonic-gate 			{
14630Sstevel@tonic-gate 				char wrkbuf[8];
14640Sstevel@tonic-gate 				int len;
14650Sstevel@tonic-gate 
14660Sstevel@tonic-gate 				kbdcmd(kbdd->kbdd_writeq, KBD_CMD_NOCLICK);
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 				bzero(wrkbuf, 8);
14690Sstevel@tonic-gate 				len = 7;
14700Sstevel@tonic-gate 				if (ddi_getlongprop_buf(DDI_DEV_T_ANY,
14710Sstevel@tonic-gate 				    ddi_root_node(), 0, "keyboard-click?",
14720Sstevel@tonic-gate 				    (caddr_t)wrkbuf, &len) ==
14730Sstevel@tonic-gate 				    DDI_PROP_SUCCESS &&
14740Sstevel@tonic-gate 				    len > 0 && len < 8) {
14750Sstevel@tonic-gate 					if (strcmp(wrkbuf, "true") == 0) {
14760Sstevel@tonic-gate 						kbdcmd(kbdd->kbdd_writeq,
1477*5129Smarx 						    KBD_CMD_CLICK);
14780Sstevel@tonic-gate 					}
14790Sstevel@tonic-gate 				}
14800Sstevel@tonic-gate 			}
14810Sstevel@tonic-gate 			break;
14820Sstevel@tonic-gate 		}
14830Sstevel@tonic-gate 		/*
14840Sstevel@tonic-gate 		 * A keyboard reset clears the LEDs.
14850Sstevel@tonic-gate 		 * Restore the LEDs from the last value we set
14860Sstevel@tonic-gate 		 * them to.
14870Sstevel@tonic-gate 		 */
14880Sstevel@tonic-gate 		kbdsetled(kbdd);
14890Sstevel@tonic-gate 		return;
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	case KID_OK:
14920Sstevel@tonic-gate 		switch (key) {
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate #if	defined(KBD_PRESSED_PREFIX)
14950Sstevel@tonic-gate 		case KBD_PRESSED_PREFIX:
14960Sstevel@tonic-gate 			k->k_idstate = KID_GOT_PRESSED;
14970Sstevel@tonic-gate 			return;
14980Sstevel@tonic-gate #endif
14990Sstevel@tonic-gate 
15000Sstevel@tonic-gate #if	defined(KBD_RELEASED_PREFIX)
15010Sstevel@tonic-gate 		case KBD_RELEASED_PREFIX:
15020Sstevel@tonic-gate 			k->k_idstate = KID_GOT_RELEASED;
15030Sstevel@tonic-gate 			return;
15040Sstevel@tonic-gate #endif
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 		case 0:
15070Sstevel@tonic-gate 			kbdreset(kbdd, HARD_RESET);
15080Sstevel@tonic-gate 			return;
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 		/*
15110Sstevel@tonic-gate 		 * we want to check for ID only if we are in
15120Sstevel@tonic-gate 		 * translatable mode.
15130Sstevel@tonic-gate 		 */
15140Sstevel@tonic-gate 		case RESETKEY:
15150Sstevel@tonic-gate 			kbdreset(kbdd, NO_HARD_RESET);
15160Sstevel@tonic-gate 			if (k->k_idstate == KID_NONE) {
15170Sstevel@tonic-gate 				k->k_idstate = KID_GOT_PREFACE;
15180Sstevel@tonic-gate 			}
15190Sstevel@tonic-gate 			return;
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 		case LAYOUTKEY:
15220Sstevel@tonic-gate 			k->k_idstate = KID_GOT_LAYOUT;
15230Sstevel@tonic-gate 			return;
15240Sstevel@tonic-gate 		}
15250Sstevel@tonic-gate 		break;
15260Sstevel@tonic-gate 
15270Sstevel@tonic-gate #if	defined(KBD_PRESSED_PREFIX)
15280Sstevel@tonic-gate 	case KID_GOT_PRESSED:
15290Sstevel@tonic-gate 		key = BUILDKEY(key, PRESSED);
15300Sstevel@tonic-gate 		k->k_idstate = KID_OK;
15310Sstevel@tonic-gate 		break;
15320Sstevel@tonic-gate #endif
15330Sstevel@tonic-gate #if	defined(KBD_RELEASED_PREFIX)
15340Sstevel@tonic-gate 	case KID_GOT_RELEASED:
15350Sstevel@tonic-gate 		key = BUILDKEY(key, RELEASED);
15360Sstevel@tonic-gate 		k->k_idstate = KID_OK;
15370Sstevel@tonic-gate 		break;
15380Sstevel@tonic-gate #endif
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 	case KID_GOT_LAYOUT:
15410Sstevel@tonic-gate 		if (kbdd->kbdd_layoutid)
15420Sstevel@tonic-gate 			(void) quntimeout(kbdd->kbdd_readq,
15430Sstevel@tonic-gate 			    kbdd->kbdd_layoutid);
15440Sstevel@tonic-gate 		if ((mp = kbdd->kbdd_replypending) != NULL) {
15450Sstevel@tonic-gate 			kbdd->kbdd_replypending = NULL;
15460Sstevel@tonic-gate 			*(int *)mp->b_cont->b_wptr = key;
15470Sstevel@tonic-gate 			mp->b_cont->b_wptr += sizeof (int);
15480Sstevel@tonic-gate 			putnext(kbdd->kbdd_readq, mp);
15490Sstevel@tonic-gate 		}
15500Sstevel@tonic-gate 		k->k_idstate = KID_OK;
15510Sstevel@tonic-gate 		return;
15520Sstevel@tonic-gate 	}
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate 	switch (k->k_state) {
15550Sstevel@tonic-gate 
15560Sstevel@tonic-gate #if defined(__sparc)
15570Sstevel@tonic-gate 	normalstate:
15580Sstevel@tonic-gate 		k->k_state = NORMAL;
15590Sstevel@tonic-gate 		/* FALLTHRU */
15600Sstevel@tonic-gate #endif
15610Sstevel@tonic-gate 	case NORMAL:
15620Sstevel@tonic-gate #if defined(__sparc)
15630Sstevel@tonic-gate 		if (k->k_curkeyboard) {
15640Sstevel@tonic-gate 			if (key == k->k_curkeyboard->k_abort1) {
15650Sstevel@tonic-gate 				k->k_state = ABORT1;
15660Sstevel@tonic-gate 				break;
15670Sstevel@tonic-gate 			}
15683505Sqz150045 			if ((key == k->k_curkeyboard->k_newabort1) ||
15693505Sqz150045 			    (key == k->k_curkeyboard->k_newabort1a)) {
15703505Sqz150045 				k->k_state = NEWABORT1;
15713927Sqz150045 				kbdd->shiftkey = key;
15723505Sqz150045 			}
15730Sstevel@tonic-gate 		}
15740Sstevel@tonic-gate #endif
15750Sstevel@tonic-gate 		kbduse(kbdd, key);
15760Sstevel@tonic-gate 		break;
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate #if defined(__sparc)
15790Sstevel@tonic-gate 	case ABORT1:
15800Sstevel@tonic-gate 		if (k->k_curkeyboard) {
15810Sstevel@tonic-gate 			/*
15820Sstevel@tonic-gate 			 * Only recognize this as an abort sequence if
15830Sstevel@tonic-gate 			 * the "hardware" console is set to be this device.
15840Sstevel@tonic-gate 			 */
15850Sstevel@tonic-gate 			if (key == k->k_curkeyboard->k_abort2 &&
15860Sstevel@tonic-gate 			    rconsvp == wsconsvp) {
15870Sstevel@tonic-gate 				DELAY(100000);
15880Sstevel@tonic-gate 				abort_sequence_enter((char *)NULL);
15890Sstevel@tonic-gate 				k->k_state = NORMAL;
15900Sstevel@tonic-gate 				kbduse(kbdd, IDLEKEY);	/* fake */
15910Sstevel@tonic-gate 				return;
15920Sstevel@tonic-gate 			} else {
15930Sstevel@tonic-gate 				kbduse(kbdd, k->k_curkeyboard->k_abort1);
15940Sstevel@tonic-gate 				goto normalstate;
15950Sstevel@tonic-gate 			}
15960Sstevel@tonic-gate 		}
15970Sstevel@tonic-gate 		break;
15983505Sqz150045 	case NEWABORT1:
15993505Sqz150045 		if (k->k_curkeyboard) {
16003505Sqz150045 			/*
16013505Sqz150045 			 * Only recognize this as an abort sequence if
16023505Sqz150045 			 * the "hardware" console is set to be this device.
16033505Sqz150045 			 */
16043505Sqz150045 			if (key == k->k_curkeyboard->k_newabort2 &&
16053505Sqz150045 			    rconsvp == wsconsvp) {
16063505Sqz150045 				DELAY(100000);
16073505Sqz150045 				abort_sequence_enter((char *)NULL);
16083505Sqz150045 				k->k_state = NORMAL;
16093927Sqz150045 				kbdd->shiftkey |= RELEASED;
16103927Sqz150045 				kbduse(kbdd, kbdd->shiftkey);
16113505Sqz150045 				kbduse(kbdd, IDLEKEY);	/* fake */
16123505Sqz150045 				return;
16133505Sqz150045 			} else {
16143505Sqz150045 				goto normalstate;
16153505Sqz150045 			}
16163505Sqz150045 		}
16173505Sqz150045 		break;
16180Sstevel@tonic-gate #endif
16190Sstevel@tonic-gate 
16200Sstevel@tonic-gate 	case COMPOSE1:
16210Sstevel@tonic-gate 	case COMPOSE2:
16220Sstevel@tonic-gate 	case FLTACCENT:
16230Sstevel@tonic-gate 		if (key != IDLEKEY)
16240Sstevel@tonic-gate 			kbduse(kbdd, key);
16250Sstevel@tonic-gate 		break;
16260Sstevel@tonic-gate 	}
16270Sstevel@tonic-gate }
16280Sstevel@tonic-gate 
16290Sstevel@tonic-gate static void
kbdid(register struct kbddata * kbdd,int id)16300Sstevel@tonic-gate kbdid(register struct kbddata *kbdd, int id)
16310Sstevel@tonic-gate {
16320Sstevel@tonic-gate 	register struct keyboardstate *k;
16330Sstevel@tonic-gate 	int	i;
16340Sstevel@tonic-gate 
16350Sstevel@tonic-gate 	k = &kbdd->kbdd_state;
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 	k->k_idstate = KID_OK;
16380Sstevel@tonic-gate 	k->k_shiftmask = 0;
16390Sstevel@tonic-gate 	k->k_buckybits = 0;
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	/*
16420Sstevel@tonic-gate 	 * Reset k_rptkey to IDLEKEY. We need to cancel
16430Sstevel@tonic-gate 	 * the autorepeat feature, if any.
16440Sstevel@tonic-gate 	 */
16450Sstevel@tonic-gate 	if (k->k_rptkey != IDLEKEY) {
16460Sstevel@tonic-gate 		if (kbdd->kbdd_rptid)
16470Sstevel@tonic-gate 			(void) quntimeout(kbdd->kbdd_readq, kbdd->kbdd_rptid);
16480Sstevel@tonic-gate 		kbdd->kbdd_rptid = 0;
16490Sstevel@tonic-gate 		k->k_rptkey = IDLEKEY;
16500Sstevel@tonic-gate 	}
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate 	k->k_curkeyboard = NULL;
16530Sstevel@tonic-gate 	for (i = 0; keytables[i].table; i++) {
16540Sstevel@tonic-gate 		if (keytables[i].id == id) {
16550Sstevel@tonic-gate 			k->k_id = id;
16560Sstevel@tonic-gate 			k->k_curkeyboard = keytables[i].table;
16570Sstevel@tonic-gate 			break;
16580Sstevel@tonic-gate 		}
16590Sstevel@tonic-gate 	}
16600Sstevel@tonic-gate 	if (!k->k_curkeyboard) {
16610Sstevel@tonic-gate 		k->k_id = keytables[0].id;
16620Sstevel@tonic-gate 		k->k_curkeyboard = keytables[0].table;
16630Sstevel@tonic-gate 		cmn_err(CE_WARN, "kbd: Unknown keyboard type, "
1664*5129Smarx 		    "Type %d assumed", k->k_id);
16650Sstevel@tonic-gate 	}
16660Sstevel@tonic-gate }
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate /*
16690Sstevel@tonic-gate  * This routine determines which table we should look in to decode
16700Sstevel@tonic-gate  * the current keycode.
16710Sstevel@tonic-gate  */
16720Sstevel@tonic-gate static struct keymap *
settable(register struct kbddata * kbdd,register uint_t mask)16730Sstevel@tonic-gate settable(register struct kbddata *kbdd, register uint_t mask)
16740Sstevel@tonic-gate {
16750Sstevel@tonic-gate 	register struct keyboard *kp;
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate 	kp = kbdd->kbdd_state.k_curkeyboard;
16780Sstevel@tonic-gate 	if (kp == NULL)
16790Sstevel@tonic-gate 		return (NULL);
16800Sstevel@tonic-gate 	if (mask & UPMASK)
16810Sstevel@tonic-gate 		return (kp->k_up);
16820Sstevel@tonic-gate 	if (mask & NUMLOCKMASK)
16830Sstevel@tonic-gate 		return (kp->k_numlock);
16840Sstevel@tonic-gate 	if (mask & CTRLMASK)
16850Sstevel@tonic-gate 		return (kp->k_control);
16860Sstevel@tonic-gate 	if (mask & ALTGRAPHMASK)
16870Sstevel@tonic-gate 		return (kp->k_altgraph);
16880Sstevel@tonic-gate 	if (mask & SHIFTMASK)
16890Sstevel@tonic-gate 		return (kp->k_shifted);
16900Sstevel@tonic-gate 	if (mask & CAPSMASK)
16910Sstevel@tonic-gate 		return (kp->k_caps);
16920Sstevel@tonic-gate 	return (kp->k_normal);
16930Sstevel@tonic-gate }
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate static void
kbdrpt(void * arg)16960Sstevel@tonic-gate kbdrpt(void *arg)
16970Sstevel@tonic-gate {
16980Sstevel@tonic-gate 	struct kbddata *kbdd = arg;
16990Sstevel@tonic-gate 	struct keyboardstate *k;
17000Sstevel@tonic-gate 
17010Sstevel@tonic-gate 	k = &kbdd->kbdd_state;
17020Sstevel@tonic-gate #ifdef	KBD_DEBUG
17030Sstevel@tonic-gate 	if (kbd_rpt_debug)
17040Sstevel@tonic-gate 		printf("kbdrpt key %x\n", k->k_rptkey);
17050Sstevel@tonic-gate #endif
17060Sstevel@tonic-gate 	kbdd->kbdd_rptid = 0;
17070Sstevel@tonic-gate 
17080Sstevel@tonic-gate 	kbdkeyreleased(kbdd, KEYOF(k->k_rptkey));
17090Sstevel@tonic-gate 	kbduse(kbdd, k->k_rptkey);
17100Sstevel@tonic-gate 	if (k->k_rptkey != IDLEKEY) {
17110Sstevel@tonic-gate 		kbdd->kbdd_rptid = qtimeout(kbdd->kbdd_readq, kbdrpt,
17120Sstevel@tonic-gate 		    kbdd, kbd_repeatrate);
17130Sstevel@tonic-gate 	}
17140Sstevel@tonic-gate }
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate static void
kbdcancelrpt(register struct kbddata * kbdd)17170Sstevel@tonic-gate kbdcancelrpt(register struct kbddata *kbdd)
17180Sstevel@tonic-gate {
17190Sstevel@tonic-gate 	register struct keyboardstate *k;
17200Sstevel@tonic-gate 
17210Sstevel@tonic-gate 	k = &kbdd->kbdd_state;
17220Sstevel@tonic-gate 	if (k->k_rptkey != IDLEKEY) {
17230Sstevel@tonic-gate 		if (kbdd->kbdd_rptid)
17240Sstevel@tonic-gate 			(void) quntimeout(kbdd->kbdd_readq, kbdd->kbdd_rptid);
17250Sstevel@tonic-gate 		kbdd->kbdd_rptid = 0;
17260Sstevel@tonic-gate 		k->k_rptkey = IDLEKEY;
17270Sstevel@tonic-gate 	}
17280Sstevel@tonic-gate 	ASSERT(kbdd->kbdd_rptid == 0);
17290Sstevel@tonic-gate }
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate static void
kbdtranslate(struct kbddata * kbdd,unsigned keycode,queue_t * q)17320Sstevel@tonic-gate kbdtranslate(struct kbddata *kbdd, unsigned keycode, queue_t *q)
17330Sstevel@tonic-gate {
17340Sstevel@tonic-gate 	register uchar_t key;
17350Sstevel@tonic-gate 	register unsigned newstate;
17360Sstevel@tonic-gate 	unsigned shiftmask;
17370Sstevel@tonic-gate 	register ushort_t entry, entrytype;
17380Sstevel@tonic-gate 	register char *cp, *bufp;
17390Sstevel@tonic-gate 	register struct keyboardstate *k;
17400Sstevel@tonic-gate 	ushort_t result_iso;
17410Sstevel@tonic-gate 	struct keymap *km;
17420Sstevel@tonic-gate 	Firm_event fe;
17430Sstevel@tonic-gate 	int i, ret_val;
17440Sstevel@tonic-gate 	char buf[14];
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 	k = &kbdd->kbdd_state;
17470Sstevel@tonic-gate 	newstate = STATEOF(keycode);
17480Sstevel@tonic-gate 	key = KEYOF(keycode);
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate #ifdef	KBD_DEBUG
17510Sstevel@tonic-gate 	if (kbd_input_debug) {
17520Sstevel@tonic-gate 		printf("KBD TRANSLATE keycode=0x%x newstate=0x%x key=0x%x\n",
17530Sstevel@tonic-gate 		    keycode, newstate, key);
17540Sstevel@tonic-gate 	}
17550Sstevel@tonic-gate #endif
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate 	if (kbdd->kbdd_translate == TR_UNTRANS_EVENT) {
17580Sstevel@tonic-gate 		if (newstate == PRESSED) {
17590Sstevel@tonic-gate 			bzero(&fe, sizeof (fe));
17600Sstevel@tonic-gate 			fe.id = key;
17610Sstevel@tonic-gate 			fe.value = 1;
17620Sstevel@tonic-gate 			kbdqueuepress(kbdd, key, &fe);
17630Sstevel@tonic-gate 		} else {
17640Sstevel@tonic-gate 			kbdkeyreleased(kbdd, key);
17650Sstevel@tonic-gate 		}
17660Sstevel@tonic-gate 		return;
17670Sstevel@tonic-gate 	}
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 	shiftmask = k->k_shiftmask;
17700Sstevel@tonic-gate 	if (newstate == RELEASED)
17710Sstevel@tonic-gate 		shiftmask |= UPMASK;
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate 	km = settable(kbdd, shiftmask);
17740Sstevel@tonic-gate 	if (km == NULL) {		/* gross error */
17750Sstevel@tonic-gate 		kbdcancelrpt(kbdd);
17760Sstevel@tonic-gate 		return;
17770Sstevel@tonic-gate 	}
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 	if (key >= KEYMAP_SIZE)
17800Sstevel@tonic-gate 		return;
17810Sstevel@tonic-gate 	entry = km->keymap[key];
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate 	if (entry == NONL) {
17840Sstevel@tonic-gate 		/*
17850Sstevel@tonic-gate 		 * NONL appears only in the Num Lock table, and indicates that
17860Sstevel@tonic-gate 		 * this key is not affected by Num Lock.  This means we should
17870Sstevel@tonic-gate 		 * ask for the table we would have gotten had Num Lock not been
17880Sstevel@tonic-gate 		 * down, and translate using that table.
17890Sstevel@tonic-gate 		 */
17900Sstevel@tonic-gate 		km = settable(kbdd, shiftmask & ~NUMLOCKMASK);
17910Sstevel@tonic-gate 		if (km == NULL) {		/* gross error */
17920Sstevel@tonic-gate 			kbdcancelrpt(kbdd);
17930Sstevel@tonic-gate 			return;
17940Sstevel@tonic-gate 		}
17950Sstevel@tonic-gate 		entry = km->keymap[key];
17960Sstevel@tonic-gate 	}
17970Sstevel@tonic-gate 	entrytype = (ushort_t)(entry & 0xFF00) >> 8;
17980Sstevel@tonic-gate 
17990Sstevel@tonic-gate 	if (entrytype == (SHIFTKEYS >> 8)) {
18000Sstevel@tonic-gate 		/*
18010Sstevel@tonic-gate 		 * Handle the state of toggle shifts specially.
18020Sstevel@tonic-gate 		 * Ups should be ignored, and downs should be mapped to ups if
18030Sstevel@tonic-gate 		 * that shift is currently on.
18040Sstevel@tonic-gate 		 */
18050Sstevel@tonic-gate 		if ((1 << (entry & 0x0F)) & k->k_curkeyboard->k_toggleshifts) {
18060Sstevel@tonic-gate 			if ((1 << (entry & 0x0F)) & k->k_togglemask) {
18070Sstevel@tonic-gate 				newstate = RELEASED;	/* toggling off */
18080Sstevel@tonic-gate 			} else {
18090Sstevel@tonic-gate 				newstate = PRESSED;	/* toggling on */
18100Sstevel@tonic-gate 			}
18110Sstevel@tonic-gate 		}
18120Sstevel@tonic-gate 	} else {
18130Sstevel@tonic-gate 		/*
18140Sstevel@tonic-gate 		 * Handle Compose and floating accent key sequences
18150Sstevel@tonic-gate 		 */
18160Sstevel@tonic-gate 		if (k->k_state == COMPOSE1) {
18170Sstevel@tonic-gate 			if (newstate == RELEASED)
18180Sstevel@tonic-gate 				return;
18190Sstevel@tonic-gate 			if (entry < ASCII_SET_SIZE) {
18200Sstevel@tonic-gate 				if (kb_compose_map[entry] >= 0) {
18210Sstevel@tonic-gate 					kbdd->compose_key = entry;
18220Sstevel@tonic-gate 					k->k_state = COMPOSE2;
18230Sstevel@tonic-gate 					return;
18240Sstevel@tonic-gate 				}
18250Sstevel@tonic-gate 			}
18260Sstevel@tonic-gate 			k->k_state = NORMAL;
18270Sstevel@tonic-gate 			kbdd->led_state &= ~LED_COMPOSE;
18280Sstevel@tonic-gate 			kbdsetled(kbdd);
18290Sstevel@tonic-gate 			return;
18300Sstevel@tonic-gate 		} else if (k->k_state == COMPOSE2) {
18310Sstevel@tonic-gate 			if (newstate == RELEASED)
18320Sstevel@tonic-gate 				return;
18330Sstevel@tonic-gate 			k->k_state = NORMAL;	/* next state is "normal" */
18340Sstevel@tonic-gate 			kbdd->led_state &= ~LED_COMPOSE;
18350Sstevel@tonic-gate 			kbdsetled(kbdd);
18360Sstevel@tonic-gate 			if (entry < ASCII_SET_SIZE) {
18370Sstevel@tonic-gate 				if (kb_compose_map[entry] >= 0) {
18380Sstevel@tonic-gate 					if (kbdd->compose_key <= entry) {
18390Sstevel@tonic-gate 						ret_val = kbd_do_compose(
1840*5129Smarx 						    kbdd->compose_key,
1841*5129Smarx 						    entry,
1842*5129Smarx 						    &result_iso);
18430Sstevel@tonic-gate 					} else {
18440Sstevel@tonic-gate 						ret_val = kbd_do_compose(
1845*5129Smarx 						    entry,
1846*5129Smarx 						    kbdd->compose_key,
1847*5129Smarx 						    &result_iso);
18480Sstevel@tonic-gate 					}
18490Sstevel@tonic-gate 					if (ret_val == 1) {
18500Sstevel@tonic-gate 						if (kbdd->kbdd_translate ==
1851*5129Smarx 						    TR_EVENT) {
18520Sstevel@tonic-gate 							fe.id =
1853*5129Smarx 							    (kbdd->kbdd_compat ?
1854*5129Smarx 							    ISO_FIRST :
1855*5129Smarx 							    EUC_FIRST)
1856*5129Smarx 							    + result_iso;
18570Sstevel@tonic-gate 							fe.value = 1;
18580Sstevel@tonic-gate 							kbdqueueevent(
1859*5129Smarx 							    kbdd,
1860*5129Smarx 							    &fe);
18610Sstevel@tonic-gate 						} else if (
1862*5129Smarx 						    kbdd->kbdd_translate ==
1863*5129Smarx 						    TR_ASCII)
18640Sstevel@tonic-gate 							kbdputcode(
1865*5129Smarx 							    result_iso,
1866*5129Smarx 							    q);
18670Sstevel@tonic-gate 					}
18680Sstevel@tonic-gate 				}
18690Sstevel@tonic-gate 			}
18700Sstevel@tonic-gate 			return;
18710Sstevel@tonic-gate 		} else if (k->k_state == FLTACCENT) {
18720Sstevel@tonic-gate 			if (newstate == RELEASED)
18730Sstevel@tonic-gate 				return;
18740Sstevel@tonic-gate 			k->k_state = NORMAL;	/* next state is "normal" */
18750Sstevel@tonic-gate 			for (i = 0;
18760Sstevel@tonic-gate 			    (kb_fltaccent_table[i].fa_entry
1877*5129Smarx 			    != kbdd->fltaccent_entry) ||
18780Sstevel@tonic-gate 			    (kb_fltaccent_table[i].ascii != entry);
18790Sstevel@tonic-gate 			    i++) {
18800Sstevel@tonic-gate 				if (kb_fltaccent_table[i].fa_entry == 0)
18810Sstevel@tonic-gate 					/* Invalid second key: ignore key */
18820Sstevel@tonic-gate 					return;
18830Sstevel@tonic-gate 			}
18840Sstevel@tonic-gate 			if (kbdd->kbdd_translate == TR_EVENT) {
18850Sstevel@tonic-gate 				fe.id = (kbdd->kbdd_compat ?
1886*5129Smarx 				    ISO_FIRST : EUC_FIRST)
1887*5129Smarx 				    + kb_fltaccent_table[i].iso;
18880Sstevel@tonic-gate 				fe.value = 1;
18890Sstevel@tonic-gate 				kbdqueueevent(kbdd, &fe);
18900Sstevel@tonic-gate 			} else if (kbdd->kbdd_translate == TR_ASCII)
18910Sstevel@tonic-gate 				kbdputcode(kb_fltaccent_table[i].iso, q);
18920Sstevel@tonic-gate 			return;
18930Sstevel@tonic-gate 		}
18940Sstevel@tonic-gate 	}
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate 	/*
18970Sstevel@tonic-gate 	 * If the key is going down, and it's not one of the keys that doesn't
18980Sstevel@tonic-gate 	 * auto-repeat, set up the auto-repeat timeout.
18990Sstevel@tonic-gate 	 *
19000Sstevel@tonic-gate 	 * The keys that don't auto-repeat are the Compose key,
19010Sstevel@tonic-gate 	 * the shift keys, the "bucky bit" keys, the "floating accent" keys,
19020Sstevel@tonic-gate 	 * and the function keys when in TR_EVENT mode.
19030Sstevel@tonic-gate 	 */
19040Sstevel@tonic-gate 	if (newstate == PRESSED && entrytype != (SHIFTKEYS >> 8) &&
19050Sstevel@tonic-gate 	    entrytype != (BUCKYBITS >> 8) && entrytype != (FUNNY >> 8) &&
19060Sstevel@tonic-gate 	    entrytype != (FA_CLASS >> 8) &&
19070Sstevel@tonic-gate 	    !((entrytype == (FUNCKEYS >> 8) || entrytype == (PADKEYS >> 8)) &&
19080Sstevel@tonic-gate 	    kbdd->kbdd_translate == TR_EVENT)) {
19090Sstevel@tonic-gate 		if (k->k_rptkey != keycode) {
19100Sstevel@tonic-gate 			kbdcancelrpt(kbdd);
19110Sstevel@tonic-gate 			kbdd->kbdd_rptid = qtimeout(q, kbdrpt, kbdd,
19120Sstevel@tonic-gate 			    kbd_repeatdelay);
19130Sstevel@tonic-gate 			k->k_rptkey = keycode;
19140Sstevel@tonic-gate 		}
19150Sstevel@tonic-gate 	} else if (key == KEYOF(k->k_rptkey))		/* key going up */
19160Sstevel@tonic-gate 		kbdcancelrpt(kbdd);
19170Sstevel@tonic-gate 	if ((newstate == RELEASED) && (kbdd->kbdd_translate == TR_EVENT))
19180Sstevel@tonic-gate 		kbdkeyreleased(kbdd, key);
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate 	/*
19210Sstevel@tonic-gate 	 * We assume here that keys other than shift keys and bucky keys have
19220Sstevel@tonic-gate 	 * entries in the "up" table that cause nothing to be done, and thus we
19230Sstevel@tonic-gate 	 * don't have to check for newstate == RELEASED.
19240Sstevel@tonic-gate 	 */
19250Sstevel@tonic-gate 	switch (entrytype) {
19260Sstevel@tonic-gate 
19270Sstevel@tonic-gate 	case 0x0:		/* regular key */
19280Sstevel@tonic-gate 		switch (kbdd->kbdd_translate) {
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate 		case TR_EVENT:
19310Sstevel@tonic-gate 			fe.id = entry | k->k_buckybits;
19320Sstevel@tonic-gate 			fe.value = 1;
19330Sstevel@tonic-gate 			kbdkeypressed(kbdd, key, &fe, entry);
19340Sstevel@tonic-gate 			break;
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 		case TR_ASCII:
19370Sstevel@tonic-gate 			kbdputcode(entry | k->k_buckybits, q);
19380Sstevel@tonic-gate 			break;
19390Sstevel@tonic-gate 		}
19400Sstevel@tonic-gate 		break;
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 	case SHIFTKEYS >> 8: {
19430Sstevel@tonic-gate 		uint_t shiftbit = 1 << (entry & 0x0F);
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate 		/* Modify toggle state (see toggle processing above) */
19460Sstevel@tonic-gate 		if (shiftbit & k->k_curkeyboard->k_toggleshifts) {
19470Sstevel@tonic-gate 			if (newstate == RELEASED) {
19480Sstevel@tonic-gate 				if (shiftbit == CAPSMASK) {
19490Sstevel@tonic-gate 					kbdd->led_state &= ~LED_CAPS_LOCK;
19500Sstevel@tonic-gate 					kbdsetled(kbdd);
19510Sstevel@tonic-gate 				} else if (shiftbit == NUMLOCKMASK) {
19520Sstevel@tonic-gate 					kbdd->led_state &= ~LED_NUM_LOCK;
19530Sstevel@tonic-gate 					kbdsetled(kbdd);
19540Sstevel@tonic-gate 				}
19550Sstevel@tonic-gate 				k->k_togglemask &= ~shiftbit;
19560Sstevel@tonic-gate 			} else {
19570Sstevel@tonic-gate 				if (shiftbit == CAPSMASK) {
19580Sstevel@tonic-gate 					kbdd->led_state |= LED_CAPS_LOCK;
19590Sstevel@tonic-gate 					kbdsetled(kbdd);
19600Sstevel@tonic-gate 				} else if (shiftbit == NUMLOCKMASK) {
19610Sstevel@tonic-gate 					kbdd->led_state |= LED_NUM_LOCK;
19620Sstevel@tonic-gate 					kbdsetled(kbdd);
19630Sstevel@tonic-gate 				}
19640Sstevel@tonic-gate 				k->k_togglemask |= shiftbit;
19650Sstevel@tonic-gate 			}
19660Sstevel@tonic-gate 		}
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate 		if (newstate == RELEASED)
19690Sstevel@tonic-gate 			k->k_shiftmask &= ~shiftbit;
19700Sstevel@tonic-gate 		else
19710Sstevel@tonic-gate 			k->k_shiftmask |= shiftbit;
19720Sstevel@tonic-gate 
19730Sstevel@tonic-gate 		if (kbdd->kbdd_translate == TR_EVENT && newstate == PRESSED) {
19740Sstevel@tonic-gate 			/*
19750Sstevel@tonic-gate 			 * Relying on ordinal correspondence between
19760Sstevel@tonic-gate 			 * vuid_event.h SHIFT_CAPSLOCK-SHIFT_RIGHTCTRL &
19770Sstevel@tonic-gate 			 * kbd.h CAPSLOCK-RIGHTCTRL in order to
19780Sstevel@tonic-gate 			 * correctly translate entry into fe.id.
19790Sstevel@tonic-gate 			 */
19800Sstevel@tonic-gate 			fe.id = SHIFT_CAPSLOCK + (entry & 0x0F);
19810Sstevel@tonic-gate 			fe.value = 1;
19820Sstevel@tonic-gate 			kbdkeypressed(kbdd, key, &fe, fe.id);
19830Sstevel@tonic-gate 		}
19840Sstevel@tonic-gate 		break;
19850Sstevel@tonic-gate 		}
19860Sstevel@tonic-gate 
19870Sstevel@tonic-gate 	case BUCKYBITS >> 8:
19880Sstevel@tonic-gate 		k->k_buckybits ^= 1 << (7 + (entry & 0x0F));
19890Sstevel@tonic-gate 		if (kbdd->kbdd_translate == TR_EVENT && newstate == PRESSED) {
19900Sstevel@tonic-gate 			/*
19910Sstevel@tonic-gate 			 * Relying on ordinal correspondence between
19920Sstevel@tonic-gate 			 * vuid_event.h SHIFT_META-SHIFT_TOP &
19930Sstevel@tonic-gate 			 * kbd.h METABIT-SYSTEMBIT in order to
19940Sstevel@tonic-gate 			 * correctly translate entry into fe.id.
19950Sstevel@tonic-gate 			 */
19960Sstevel@tonic-gate 			fe.id = SHIFT_META + (entry & 0x0F);
19970Sstevel@tonic-gate 			fe.value = 1;
19980Sstevel@tonic-gate 			kbdkeypressed(kbdd, key, &fe, fe.id);
19990Sstevel@tonic-gate 		}
20000Sstevel@tonic-gate 		break;
20010Sstevel@tonic-gate 
20020Sstevel@tonic-gate 	case FUNNY >> 8:
20030Sstevel@tonic-gate 		switch (entry) {
20040Sstevel@tonic-gate 		case NOP:
20050Sstevel@tonic-gate 			break;
20060Sstevel@tonic-gate 
20070Sstevel@tonic-gate 		case IDLE:
20080Sstevel@tonic-gate 			/* Fall thru into RESET code */
20090Sstevel@tonic-gate 			/* FALLTHRU */
20100Sstevel@tonic-gate 		case RESET:
20110Sstevel@tonic-gate 		gotreset:
20120Sstevel@tonic-gate 			k->k_shiftmask &= k->k_curkeyboard->k_idleshifts;
20130Sstevel@tonic-gate 			k->k_shiftmask |= k->k_togglemask;
20140Sstevel@tonic-gate 			k->k_buckybits &= k->k_curkeyboard->k_idlebuckys;
20150Sstevel@tonic-gate 			kbdcancelrpt(kbdd);
20160Sstevel@tonic-gate 			kbdreleaseall(kbdd);
20170Sstevel@tonic-gate 			break;
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate 		case ERROR:
20200Sstevel@tonic-gate 			cmn_err(CE_WARN, "kbd: Error detected");
20210Sstevel@tonic-gate 			goto gotreset;
20220Sstevel@tonic-gate 
20230Sstevel@tonic-gate 		case COMPOSE:
20240Sstevel@tonic-gate 			k->k_state = COMPOSE1;
20250Sstevel@tonic-gate 			kbdd->led_state |= LED_COMPOSE;
20260Sstevel@tonic-gate 			kbdsetled(kbdd);
20270Sstevel@tonic-gate 			break;
20280Sstevel@tonic-gate 		/*
20290Sstevel@tonic-gate 		 * Remember when adding new entries that,
20300Sstevel@tonic-gate 		 * if they should NOT auto-repeat,
20310Sstevel@tonic-gate 		 * they should be put into the IF statement
20320Sstevel@tonic-gate 		 * just above this switch block.
20330Sstevel@tonic-gate 		 */
20340Sstevel@tonic-gate 		default:
20350Sstevel@tonic-gate 			goto badentry;
20360Sstevel@tonic-gate 		}
20370Sstevel@tonic-gate 		break;
20380Sstevel@tonic-gate 
20390Sstevel@tonic-gate 	case FA_CLASS >> 8:
20400Sstevel@tonic-gate 		if (k->k_state == NORMAL) {
20410Sstevel@tonic-gate 			kbdd->fltaccent_entry = entry;
20420Sstevel@tonic-gate 			k->k_state = FLTACCENT;
20430Sstevel@tonic-gate 		}
20440Sstevel@tonic-gate 		return;
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate 	case STRING >> 8:
20470Sstevel@tonic-gate 		cp = &keystringtab[entry & 0x0F][0];
20480Sstevel@tonic-gate 		while (*cp != '\0') {
20490Sstevel@tonic-gate 			switch (kbdd->kbdd_translate) {
20500Sstevel@tonic-gate 
20510Sstevel@tonic-gate 			case TR_EVENT:
20520Sstevel@tonic-gate 				kbd_send_esc_event(*cp, kbdd);
20530Sstevel@tonic-gate 				break;
20540Sstevel@tonic-gate 
20550Sstevel@tonic-gate 			case TR_ASCII:
20560Sstevel@tonic-gate 				kbdputcode((uchar_t)*cp, q);
20570Sstevel@tonic-gate 				break;
20580Sstevel@tonic-gate 			}
20590Sstevel@tonic-gate 			cp++;
20600Sstevel@tonic-gate 		}
20610Sstevel@tonic-gate 		break;
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate 	case FUNCKEYS >> 8:
20640Sstevel@tonic-gate 		switch (kbdd->kbdd_translate) {
20650Sstevel@tonic-gate 
20660Sstevel@tonic-gate 		case TR_ASCII:
20670Sstevel@tonic-gate 			bufp = buf;
20680Sstevel@tonic-gate 			cp = strsetwithdecimal(bufp + 2,
2069*5129Smarx 			    (uint_t)((entry & 0x003F) + 192),
2070*5129Smarx 			    sizeof (buf) - 5);
20710Sstevel@tonic-gate 			*bufp++ = '\033'; /* Escape */
20720Sstevel@tonic-gate 			*bufp++ = '[';
20730Sstevel@tonic-gate 			while (*cp != '\0')
20740Sstevel@tonic-gate 				*bufp++ = *cp++;
20750Sstevel@tonic-gate 			*bufp++ = 'z';
20760Sstevel@tonic-gate 			*bufp = '\0';
20770Sstevel@tonic-gate 			kbdputbuf(buf, q);
20780Sstevel@tonic-gate 			break;
20790Sstevel@tonic-gate 
20800Sstevel@tonic-gate 		case TR_EVENT:
20810Sstevel@tonic-gate 			/*
20820Sstevel@tonic-gate 			 * Take advantage of the similar
20830Sstevel@tonic-gate 			 * ordering of kbd.h function keys and
20840Sstevel@tonic-gate 			 * vuid_event.h function keys to do a
20850Sstevel@tonic-gate 			 * simple translation to achieve a
20860Sstevel@tonic-gate 			 * mapping between the 2 different
20870Sstevel@tonic-gate 			 * address spaces.
20880Sstevel@tonic-gate 			 */
20890Sstevel@tonic-gate 			fe.id = (entry & 0x003F) + KEY_LEFTFIRST;
20900Sstevel@tonic-gate 			fe.value = 1;
20910Sstevel@tonic-gate 			/*
20920Sstevel@tonic-gate 			 * Assume "up" table only generates
20930Sstevel@tonic-gate 			 * shift changes.
20940Sstevel@tonic-gate 			 */
20950Sstevel@tonic-gate 			kbdkeypressed(kbdd, key, &fe, fe.id);
20960Sstevel@tonic-gate 			/*
20970Sstevel@tonic-gate 			 * Function key events can be expanded
20980Sstevel@tonic-gate 			 * by terminal emulator software to
20990Sstevel@tonic-gate 			 * produce the standard escape sequence
21000Sstevel@tonic-gate 			 * generated by the TR_ASCII case above
21010Sstevel@tonic-gate 			 * if a function key event is not used
21020Sstevel@tonic-gate 			 * by terminal emulator software
21030Sstevel@tonic-gate 			 * directly.
21040Sstevel@tonic-gate 			 */
21050Sstevel@tonic-gate 			break;
21060Sstevel@tonic-gate 		}
21070Sstevel@tonic-gate 		break;
21080Sstevel@tonic-gate 
21090Sstevel@tonic-gate 	/*
21100Sstevel@tonic-gate 	 * Remember when adding new entries that,
21110Sstevel@tonic-gate 	 * if they should NOT auto-repeat,
21120Sstevel@tonic-gate 	 * they should be put into the IF statement
21130Sstevel@tonic-gate 	 * just above this switch block.
21140Sstevel@tonic-gate 	 */
21150Sstevel@tonic-gate 	case PADKEYS >> 8:
21160Sstevel@tonic-gate 		switch (kbdd->kbdd_translate) {
21170Sstevel@tonic-gate 
21180Sstevel@tonic-gate 		case TR_ASCII:
21190Sstevel@tonic-gate 			kbdputcode(kb_numlock_table[entry&0x1F], q);
21200Sstevel@tonic-gate 			break;
21210Sstevel@tonic-gate 
21220Sstevel@tonic-gate 		case TR_EVENT:
21230Sstevel@tonic-gate 			/*
21240Sstevel@tonic-gate 			 * Take advantage of the similar
21250Sstevel@tonic-gate 			 * ordering of kbd.h keypad keys and
21260Sstevel@tonic-gate 			 * vuid_event.h keypad keys to do a
21270Sstevel@tonic-gate 			 * simple translation to achieve a
21280Sstevel@tonic-gate 			 * mapping between the 2 different
21290Sstevel@tonic-gate 			 * address spaces.
21300Sstevel@tonic-gate 			 */
21310Sstevel@tonic-gate 			fe.id = (entry & 0x001F) + VKEY_FIRSTPAD;
21320Sstevel@tonic-gate 			fe.value = 1;
21330Sstevel@tonic-gate 			/*
21340Sstevel@tonic-gate 			 * Assume "up" table only generates
21350Sstevel@tonic-gate 			 * shift changes.
21360Sstevel@tonic-gate 			 */
21370Sstevel@tonic-gate 			kbdkeypressed(kbdd, key, &fe, fe.id);
21380Sstevel@tonic-gate 			/*
21390Sstevel@tonic-gate 			 * Keypad key events can be expanded
21400Sstevel@tonic-gate 			 * by terminal emulator software to
21410Sstevel@tonic-gate 			 * produce the standard ascii character
21420Sstevel@tonic-gate 			 * generated by the TR_ASCII case above
21430Sstevel@tonic-gate 			 * if a keypad key event is not used
21440Sstevel@tonic-gate 			 * by terminal emulator software
21450Sstevel@tonic-gate 			 * directly.
21460Sstevel@tonic-gate 			 */
21470Sstevel@tonic-gate 			break;
21480Sstevel@tonic-gate 		}
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate 	badentry:
21510Sstevel@tonic-gate 		break;
21520Sstevel@tonic-gate 	}
21530Sstevel@tonic-gate }
21540Sstevel@tonic-gate 
21550Sstevel@tonic-gate static int
kbd_do_compose(ushort_t first_entry,ushort_t second_entry,ushort_t * result_iso_ptr)21560Sstevel@tonic-gate kbd_do_compose(ushort_t first_entry, ushort_t second_entry,
21570Sstevel@tonic-gate 	ushort_t *result_iso_ptr)
21580Sstevel@tonic-gate {
21590Sstevel@tonic-gate 	struct compose_sequence_t *ptr;
21600Sstevel@tonic-gate 
21610Sstevel@tonic-gate 	ptr = &kb_compose_table[kb_compose_map[first_entry]];
21620Sstevel@tonic-gate 	while (ptr->first == first_entry) {
21630Sstevel@tonic-gate 		if (ptr->second == second_entry) {
21640Sstevel@tonic-gate 			*result_iso_ptr = ptr->iso;
21650Sstevel@tonic-gate 			return (1);
21660Sstevel@tonic-gate 		}
21670Sstevel@tonic-gate 		ptr++;
21680Sstevel@tonic-gate 	}
21690Sstevel@tonic-gate 	return (0);
21700Sstevel@tonic-gate }
21710Sstevel@tonic-gate 
21720Sstevel@tonic-gate static void
kbd_send_esc_event(char c,register struct kbddata * kbdd)21730Sstevel@tonic-gate kbd_send_esc_event(char c, register struct kbddata *kbdd)
21740Sstevel@tonic-gate {
21750Sstevel@tonic-gate 	Firm_event fe;
21760Sstevel@tonic-gate 
21770Sstevel@tonic-gate 	fe.id = c;
21780Sstevel@tonic-gate 	fe.value = 1;
21790Sstevel@tonic-gate 	fe.pair_type = FE_PAIR_NONE;
21800Sstevel@tonic-gate 	fe.pair = 0;
21810Sstevel@tonic-gate 	/*
21820Sstevel@tonic-gate 	 * Pretend as if each cp pushed and released
21830Sstevel@tonic-gate 	 * Calling kbdqueueevent avoids addr translation
21840Sstevel@tonic-gate 	 * and pair base determination of kbdkeypressed.
21850Sstevel@tonic-gate 	 */
21860Sstevel@tonic-gate 	kbdqueueevent(kbdd, &fe);
21870Sstevel@tonic-gate 	fe.value = 0;
21880Sstevel@tonic-gate 	kbdqueueevent(kbdd, &fe);
21890Sstevel@tonic-gate }
21900Sstevel@tonic-gate 
21910Sstevel@tonic-gate char *
strsetwithdecimal(char * buf,uint_t val,uint_t maxdigs)21920Sstevel@tonic-gate strsetwithdecimal(char *buf, uint_t val, uint_t maxdigs)
21930Sstevel@tonic-gate {
21940Sstevel@tonic-gate 	int	hradix = 5;
21950Sstevel@tonic-gate 	char	*bp;
21960Sstevel@tonic-gate 	int	lowbit;
21970Sstevel@tonic-gate 	char	*tab = "0123456789abcdef";
21980Sstevel@tonic-gate 
21990Sstevel@tonic-gate 	bp = buf + maxdigs;
22000Sstevel@tonic-gate 	*(--bp) = '\0';
22010Sstevel@tonic-gate 	while (val) {
22020Sstevel@tonic-gate 		lowbit = val & 1;
22030Sstevel@tonic-gate 		val = (val >> 1);
22040Sstevel@tonic-gate 		*(--bp) = tab[val % hradix * 2 + lowbit];
22050Sstevel@tonic-gate 		val /= hradix;
22060Sstevel@tonic-gate 	}
22070Sstevel@tonic-gate 	return (bp);
22080Sstevel@tonic-gate }
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate static void
kbdkeypressed(struct kbddata * kbdd,uchar_t key_station,Firm_event * fe,ushort_t base)22110Sstevel@tonic-gate kbdkeypressed(struct kbddata *kbdd, uchar_t key_station, Firm_event *fe,
22120Sstevel@tonic-gate     ushort_t base)
22130Sstevel@tonic-gate {
22140Sstevel@tonic-gate 	register struct keyboardstate *k;
22150Sstevel@tonic-gate 	register short id_addr;
22160Sstevel@tonic-gate 
22170Sstevel@tonic-gate 	/* Set pair values */
22180Sstevel@tonic-gate 	if (fe->id < (ushort_t)VKEY_FIRST) {
22190Sstevel@tonic-gate 		/*
22200Sstevel@tonic-gate 		 * If CTRLed, find the ID that would have been used had it
22210Sstevel@tonic-gate 		 * not been CTRLed.
22220Sstevel@tonic-gate 		 */
22230Sstevel@tonic-gate 		k = &kbdd->kbdd_state;
22240Sstevel@tonic-gate 		if (k->k_shiftmask & (CTRLMASK | CTLSMASK)) {
22250Sstevel@tonic-gate 			struct keymap *km;
22260Sstevel@tonic-gate 
22270Sstevel@tonic-gate 			km = settable(kbdd,
22280Sstevel@tonic-gate 			    k->k_shiftmask & ~(CTRLMASK | CTLSMASK | UPMASK));
22290Sstevel@tonic-gate 			if (km == NULL)
22300Sstevel@tonic-gate 				return;
22310Sstevel@tonic-gate 			base = km->keymap[key_station];
22320Sstevel@tonic-gate 		}
22330Sstevel@tonic-gate 		if (base != fe->id) {
22340Sstevel@tonic-gate 			fe->pair_type = FE_PAIR_SET;
22350Sstevel@tonic-gate 			fe->pair = base;
22360Sstevel@tonic-gate 			goto send;
22370Sstevel@tonic-gate 		}
22380Sstevel@tonic-gate 	}
22390Sstevel@tonic-gate 	fe->pair_type = FE_PAIR_NONE;
22400Sstevel@tonic-gate 	fe->pair = 0;
22410Sstevel@tonic-gate send:
22420Sstevel@tonic-gate 	/* Adjust event id address for multiple keyboard/workstation support */
22430Sstevel@tonic-gate 	switch (vuid_id_addr(fe->id)) {
22440Sstevel@tonic-gate 	case ASCII_FIRST:
22450Sstevel@tonic-gate 		id_addr = kbdd->kbdd_ascii_addr;
22460Sstevel@tonic-gate 		break;
22470Sstevel@tonic-gate 	case TOP_FIRST:
22480Sstevel@tonic-gate 		id_addr = kbdd->kbdd_top_addr;
22490Sstevel@tonic-gate 		break;
22500Sstevel@tonic-gate 	case VKEY_FIRST:
22510Sstevel@tonic-gate 		id_addr = kbdd->kbdd_vkey_addr;
22520Sstevel@tonic-gate 		break;
22530Sstevel@tonic-gate 	default:
22540Sstevel@tonic-gate 		id_addr = vuid_id_addr(fe->id);
22550Sstevel@tonic-gate 	}
22560Sstevel@tonic-gate 	fe->id = vuid_id_offset(fe->id) | id_addr;
22570Sstevel@tonic-gate 	kbdqueuepress(kbdd, key_station, fe);
22580Sstevel@tonic-gate }
22590Sstevel@tonic-gate 
22600Sstevel@tonic-gate static void
kbdqueuepress(struct kbddata * kbdd,uchar_t key_station,Firm_event * fe)22610Sstevel@tonic-gate kbdqueuepress(struct kbddata *kbdd, uchar_t key_station, Firm_event *fe)
22620Sstevel@tonic-gate {
22630Sstevel@tonic-gate 	register struct key_event *ke, *ke_free;
22640Sstevel@tonic-gate 	register int i;
22650Sstevel@tonic-gate 
22660Sstevel@tonic-gate 	if (key_station == IDLEKEY)
22670Sstevel@tonic-gate 		return;
22680Sstevel@tonic-gate #ifdef	KBD_DEBUG
22690Sstevel@tonic-gate 	if (kbd_input_debug) printf("KBD PRESSED key=%d\n", key_station);
22700Sstevel@tonic-gate #endif
22710Sstevel@tonic-gate 	ke_free = 0;
22720Sstevel@tonic-gate 	/* Scan table of down key stations */
22730Sstevel@tonic-gate 	if (kbdd->kbdd_translate == TR_EVENT ||
22740Sstevel@tonic-gate 	    kbdd->kbdd_translate == TR_UNTRANS_EVENT) {
22750Sstevel@tonic-gate 		for (i = 0, ke = kbdd->kbdd_downs;
22760Sstevel@tonic-gate 		    i < kbdd->kbdd_downs_entries;
22770Sstevel@tonic-gate 		    i++, ke++) {
22780Sstevel@tonic-gate 			/* Keycode already down? */
22790Sstevel@tonic-gate 			if (ke->key_station == key_station) {
22800Sstevel@tonic-gate #ifdef	KBD_DEBUG
22810Sstevel@tonic-gate 	printf("kbd: Double entry in downs table (%d,%d)!\n", key_station, i);
22820Sstevel@tonic-gate #endif
22830Sstevel@tonic-gate 				goto add_event;
22840Sstevel@tonic-gate 			}
22850Sstevel@tonic-gate 			if (ke->key_station == 0)
22860Sstevel@tonic-gate 				ke_free = ke;
22870Sstevel@tonic-gate 		}
22880Sstevel@tonic-gate 		if (ke_free) {
22890Sstevel@tonic-gate 			ke = ke_free;
22900Sstevel@tonic-gate 			goto add_event;
22910Sstevel@tonic-gate 		}
22920Sstevel@tonic-gate 		cmn_err(CE_WARN, "kbd: Too many keys down!");
22930Sstevel@tonic-gate 		ke = kbdd->kbdd_downs;
22940Sstevel@tonic-gate 	}
22950Sstevel@tonic-gate add_event:
22960Sstevel@tonic-gate 	ke->key_station = key_station;
22970Sstevel@tonic-gate 	ke->event = *fe;
22980Sstevel@tonic-gate 	kbdqueueevent(kbdd, fe);
22990Sstevel@tonic-gate }
23000Sstevel@tonic-gate 
23010Sstevel@tonic-gate static void
kbdkeyreleased(register struct kbddata * kbdd,uchar_t key_station)23020Sstevel@tonic-gate kbdkeyreleased(register struct kbddata *kbdd, uchar_t key_station)
23030Sstevel@tonic-gate {
23040Sstevel@tonic-gate 	register struct key_event *ke;
23050Sstevel@tonic-gate 	register int i;
23060Sstevel@tonic-gate 
23070Sstevel@tonic-gate 	if (key_station == IDLEKEY)
23080Sstevel@tonic-gate 		return;
23090Sstevel@tonic-gate #ifdef	KBD_DEBUG
23100Sstevel@tonic-gate 	if (kbd_input_debug)
23110Sstevel@tonic-gate 		printf("KBD RELEASE key=%d\n", key_station);
23120Sstevel@tonic-gate #endif
23130Sstevel@tonic-gate 	if (kbdd->kbdd_translate != TR_EVENT &&
23140Sstevel@tonic-gate 	    kbdd->kbdd_translate != TR_UNTRANS_EVENT)
23150Sstevel@tonic-gate 		return;
23160Sstevel@tonic-gate 	/* Scan table of down key stations */
23170Sstevel@tonic-gate 	for (i = 0, ke = kbdd->kbdd_downs;
23180Sstevel@tonic-gate 	    i < kbdd->kbdd_downs_entries;
23190Sstevel@tonic-gate 	    i++, ke++) {
23200Sstevel@tonic-gate 		/* Found? */
23210Sstevel@tonic-gate 		if (ke->key_station == key_station) {
23220Sstevel@tonic-gate 			ke->key_station = 0;
23230Sstevel@tonic-gate 			ke->event.value = 0;
23240Sstevel@tonic-gate 			kbdqueueevent(kbdd, &ke->event);
23250Sstevel@tonic-gate 		}
23260Sstevel@tonic-gate 	}
23270Sstevel@tonic-gate 
23280Sstevel@tonic-gate 	/*
23290Sstevel@tonic-gate 	 * Ignore if couldn't find because may be called twice
23300Sstevel@tonic-gate 	 * for the same key station in the case of the kbdrpt
23310Sstevel@tonic-gate 	 * routine being called unnecessarily.
23320Sstevel@tonic-gate 	 */
23330Sstevel@tonic-gate }
23340Sstevel@tonic-gate 
23350Sstevel@tonic-gate static void
kbdreleaseall(struct kbddata * kbdd)23360Sstevel@tonic-gate kbdreleaseall(struct kbddata *kbdd)
23370Sstevel@tonic-gate {
23380Sstevel@tonic-gate 	register struct key_event *ke;
23390Sstevel@tonic-gate 	register int i;
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate #ifdef	KBD_DEBUG
23420Sstevel@tonic-gate 	if (kbd_debug && kbd_ra_debug) printf("KBD RELEASE ALL\n");
23430Sstevel@tonic-gate #endif
23440Sstevel@tonic-gate 	/* Scan table of down key stations */
23450Sstevel@tonic-gate 	for (i = 0, ke = kbdd->kbdd_downs;
23460Sstevel@tonic-gate 	    i < kbdd->kbdd_downs_entries; i++, ke++) {
23470Sstevel@tonic-gate 		/* Key station not zero */
23480Sstevel@tonic-gate 		if (ke->key_station)
23490Sstevel@tonic-gate 			kbdkeyreleased(kbdd, ke->key_station);
23500Sstevel@tonic-gate 			/* kbdkeyreleased resets kbdd_downs entry */
23510Sstevel@tonic-gate 	}
23520Sstevel@tonic-gate }
23530Sstevel@tonic-gate 
23540Sstevel@tonic-gate /*
23550Sstevel@tonic-gate  * Pass a keycode up the stream, if you can, otherwise throw it away.
23560Sstevel@tonic-gate  */
23570Sstevel@tonic-gate static void
kbdputcode(uint_t code,queue_t * q)23580Sstevel@tonic-gate kbdputcode(uint_t code, queue_t *q)
23590Sstevel@tonic-gate {
23600Sstevel@tonic-gate 	register mblk_t *bp;
23610Sstevel@tonic-gate 
23620Sstevel@tonic-gate 	if (!canput(q))
23630Sstevel@tonic-gate 		cmn_err(CE_WARN, "kbdputcode: Can't put block for keycode");
23640Sstevel@tonic-gate 	else {
23650Sstevel@tonic-gate 		if ((bp = allocb(sizeof (uint_t), BPRI_HI)) == NULL)
23660Sstevel@tonic-gate 			cmn_err(CE_WARN,
23670Sstevel@tonic-gate 			    "kbdputcode: Can't allocate block for keycode");
23680Sstevel@tonic-gate 		else {
23690Sstevel@tonic-gate 			*bp->b_wptr++ = code;
23700Sstevel@tonic-gate 			putnext(q, bp);
23710Sstevel@tonic-gate 		}
23720Sstevel@tonic-gate 	}
23730Sstevel@tonic-gate }
23740Sstevel@tonic-gate 
23750Sstevel@tonic-gate /*
23760Sstevel@tonic-gate  * Pass  generated keycode sequence to upstream, if possible.
23770Sstevel@tonic-gate  */
23780Sstevel@tonic-gate static void
kbdputbuf(char * buf,queue_t * q)23790Sstevel@tonic-gate kbdputbuf(char *buf, queue_t *q)
23800Sstevel@tonic-gate {
23810Sstevel@tonic-gate 	register mblk_t *bp;
23820Sstevel@tonic-gate 
23830Sstevel@tonic-gate 	if (!canput(q))
23840Sstevel@tonic-gate 		cmn_err(CE_WARN, "kbdputbuf: Can't put block for keycode");
23850Sstevel@tonic-gate 	else {
23860Sstevel@tonic-gate 		if ((bp = allocb((int)strlen(buf), BPRI_HI)) == NULL)
23870Sstevel@tonic-gate 			cmn_err(CE_WARN,
2388*5129Smarx 			    "kbdputbuf: Can't allocate block for keycode");
23890Sstevel@tonic-gate 		else {
23900Sstevel@tonic-gate 			while (*buf) {
23910Sstevel@tonic-gate 				*bp->b_wptr++ = *buf;
23920Sstevel@tonic-gate 				buf++;
23930Sstevel@tonic-gate 			}
23940Sstevel@tonic-gate 			putnext(q, bp);
23950Sstevel@tonic-gate 		}
23960Sstevel@tonic-gate 	}
23970Sstevel@tonic-gate }
23980Sstevel@tonic-gate 
23990Sstevel@tonic-gate /*
24000Sstevel@tonic-gate  * Pass a VUID "firm event" up the stream, if you can.
24010Sstevel@tonic-gate  */
24020Sstevel@tonic-gate static void
kbdqueueevent(struct kbddata * kbdd,Firm_event * fe)24030Sstevel@tonic-gate kbdqueueevent(struct kbddata *kbdd, Firm_event *fe)
24040Sstevel@tonic-gate {
24050Sstevel@tonic-gate 	register queue_t *q;
24060Sstevel@tonic-gate 	register mblk_t *bp;
24070Sstevel@tonic-gate 
24080Sstevel@tonic-gate 	if ((q = kbdd->kbdd_readq) == NULL)
24090Sstevel@tonic-gate 		return;
24100Sstevel@tonic-gate 	if (!canput(q)) {
24110Sstevel@tonic-gate 		if (kbd_overflow_msg)
24120Sstevel@tonic-gate 			cmn_err(CE_WARN,
2413*5129Smarx 			    "kbd: Buffer flushed when overflowed");
24140Sstevel@tonic-gate 		kbdflush(kbdd);
24150Sstevel@tonic-gate 		kbd_overflow_cnt++;
24160Sstevel@tonic-gate 	} else {
24170Sstevel@tonic-gate 		if ((bp = allocb(sizeof (Firm_event), BPRI_HI)) == NULL)
24180Sstevel@tonic-gate 			cmn_err(CE_WARN,
24190Sstevel@tonic-gate 			    "kbdqueueevent: Can't allocate block for event");
24200Sstevel@tonic-gate 		else {
24210Sstevel@tonic-gate #if 1 /* XX64 */
24220Sstevel@tonic-gate 			struct timeval now;
24230Sstevel@tonic-gate 
24240Sstevel@tonic-gate 			/*
24250Sstevel@tonic-gate 			 * XX64: This is something of a compromise.  It
24260Sstevel@tonic-gate 			 * seems justifiable based on the usage of these
24270Sstevel@tonic-gate 			 * timestamps as an ordering relation as opposed
24280Sstevel@tonic-gate 			 * to a strict timing thing.
24290Sstevel@tonic-gate 			 *
24300Sstevel@tonic-gate 			 * But should we restore Firm_event's time stamp
24310Sstevel@tonic-gate 			 * to be a timeval, and send 32-bit and 64-bit
24320Sstevel@tonic-gate 			 * events up the pipe?
24330Sstevel@tonic-gate 			 */
24340Sstevel@tonic-gate 			uniqtime(&now);
24350Sstevel@tonic-gate 			TIMEVAL_TO_TIMEVAL32(&fe->time, &now);
24360Sstevel@tonic-gate #else
24370Sstevel@tonic-gate 			uniqtime(&fe->time);
24380Sstevel@tonic-gate #endif
24390Sstevel@tonic-gate 			*(Firm_event *)bp->b_wptr = *fe;
24400Sstevel@tonic-gate 			bp->b_wptr += sizeof (Firm_event);
24410Sstevel@tonic-gate 			putnext(q, bp);
24420Sstevel@tonic-gate 		}
24430Sstevel@tonic-gate 	}
24440Sstevel@tonic-gate }
2445