17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * Generic keyboard support: translation
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  * This module is project private.  Please see PSARC/1998/176 and
317c478bd9Sstevel@tonic-gate  * PSARC/1998/026 for references to the kbtrans module.
327c478bd9Sstevel@tonic-gate  *
337c478bd9Sstevel@tonic-gate  * It is believed that it is safe to call these functions within debugger mode
347c478bd9Sstevel@tonic-gate  * except kbtrans_dprintf.  Debugger mode is a single threaded mode where most
357c478bd9Sstevel@tonic-gate  * kernel services are not available, including memory allocation.  Debugger
367c478bd9Sstevel@tonic-gate  * mode is for kmdb and OBP debugging, where the debugger calls back into the
377c478bd9Sstevel@tonic-gate  * kernel to obtain console input.
387c478bd9Sstevel@tonic-gate  *
397c478bd9Sstevel@tonic-gate  * Please be _very_ careful about what external functions you call.
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #define	KEYMAP_SIZE_VARIABLE
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include <sys/types.h>
457c478bd9Sstevel@tonic-gate #include <sys/cred.h>
467c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
477c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
487c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
497c478bd9Sstevel@tonic-gate #include <sys/kbd.h>
507c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
517c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
527c478bd9Sstevel@tonic-gate #include <sys/kbio.h>
537c478bd9Sstevel@tonic-gate #include <sys/vuid_event.h>
547c478bd9Sstevel@tonic-gate #include <sys/consdev.h>
557c478bd9Sstevel@tonic-gate #include <sys/kbtrans.h>
567c478bd9Sstevel@tonic-gate #include <sys/errno.h>
577c478bd9Sstevel@tonic-gate #include <sys/promif.h>
587c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
597c478bd9Sstevel@tonic-gate #include "kbtrans_lower.h"
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * Internal Function Prototypes
637c478bd9Sstevel@tonic-gate  */
64*adc2b73dSToomas Soome static boolean_t kbtrans_do_compose(struct kbtrans_lower *, keymap_entry_t,
65*adc2b73dSToomas Soome     keymap_entry_t, keymap_entry_t *);
66*adc2b73dSToomas Soome static void kbtrans_translate(struct kbtrans_lower *,
67*adc2b73dSToomas Soome     struct keyboard_callback *, kbtrans_key_t, enum keystate);
68*adc2b73dSToomas Soome 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * kbtrans_processkey:
717c478bd9Sstevel@tonic-gate  *
727c478bd9Sstevel@tonic-gate  * 	lower	- state information used by the calling driver
737c478bd9Sstevel@tonic-gate  *		  this parameter is passed back to the callback routines.
747c478bd9Sstevel@tonic-gate  * 	key	- scancode
757c478bd9Sstevel@tonic-gate  * 	state	- KEY_PRESSED / KEY_RELEASED
767c478bd9Sstevel@tonic-gate  *
777c478bd9Sstevel@tonic-gate  * This routine checks to see if there is a raw callback, and calls it
787c478bd9Sstevel@tonic-gate  * if it exists.  If there is no raw callback, the key is translated.
797c478bd9Sstevel@tonic-gate  * The raw callback allows the driver that called the translation module
807c478bd9Sstevel@tonic-gate  * to be passed untranslated scancodes.
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate void
kbtrans_processkey(struct kbtrans_lower * lower,struct keyboard_callback * cb,kbtrans_key_t key,enum keystate state)837c478bd9Sstevel@tonic-gate kbtrans_processkey(struct kbtrans_lower *lower,
84*adc2b73dSToomas Soome     struct keyboard_callback *cb, kbtrans_key_t key, enum keystate state)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	DPRINTF(PRINT_L0, PRINT_MASK_ALL, (lower, "kbtrans_processkey: "
87*adc2b73dSToomas Soome 	    "newstate=%d key=%d", state, key));
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	/*
907c478bd9Sstevel@tonic-gate 	 * If there is a raw routine, then call it and return.
917c478bd9Sstevel@tonic-gate 	 */
927c478bd9Sstevel@tonic-gate 	if (cb->kc_keypressed_raw != NULL) {
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 		if (state == KEY_PRESSED) {
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 			cb->kc_keypressed_raw(lower->kbtrans_upper, key);
977c478bd9Sstevel@tonic-gate 		} else {
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 			cb->kc_keyreleased_raw(lower->kbtrans_upper, key);
1007c478bd9Sstevel@tonic-gate 		}
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 		return;
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	/*
1067c478bd9Sstevel@tonic-gate 	 * translate the scancode into a key.
1077c478bd9Sstevel@tonic-gate 	 */
1087c478bd9Sstevel@tonic-gate 	kbtrans_translate(lower, cb, key, state);
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate  * kbtrans_translate:
1147c478bd9Sstevel@tonic-gate  *
1157c478bd9Sstevel@tonic-gate  * 	lower	- state information used by the calling driver
1167c478bd9Sstevel@tonic-gate  *		  this parameter is passed back to the callback routines.
1177c478bd9Sstevel@tonic-gate  * 	key		- scan code
1187c478bd9Sstevel@tonic-gate  * 	state	- KEY_PRESSED / KEY_RELEASED
1197c478bd9Sstevel@tonic-gate  *
1207c478bd9Sstevel@tonic-gate  * Called to process key events if we are in TR_ASCII or TR_EVENT
1217c478bd9Sstevel@tonic-gate  * (sunview) mode.  This routine will call the appropriate translation_callback
1227c478bd9Sstevel@tonic-gate  * for the character when it is done translating it.
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate static void
kbtrans_translate(struct kbtrans_lower * lower,struct keyboard_callback * cb,kbtrans_key_t key,enum keystate newstate)125*adc2b73dSToomas Soome kbtrans_translate(struct kbtrans_lower *lower, struct keyboard_callback *cb,
126*adc2b73dSToomas Soome     kbtrans_key_t key, enum keystate newstate)
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate 	unsigned		shiftmask;
129*adc2b73dSToomas Soome 	register keymap_entry_t	entry;
130*adc2b73dSToomas Soome 	register unsigned	entrytype;
131*adc2b73dSToomas Soome 	keymap_entry_t		result;
132*adc2b73dSToomas Soome 	keymap_entry_t		*ke;
1337c478bd9Sstevel@tonic-gate 	int			i;
1347c478bd9Sstevel@tonic-gate 	boolean_t		good_compose;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	DPRINTF(PRINT_L0, PRINT_MASK_ALL, (lower, "KEY TRANSLATE "
137*adc2b73dSToomas Soome 	    "newstate=0x%x key=0x%x\n", newstate, key));
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	if (lower->kbtrans_keyboard == NULL) {
1407c478bd9Sstevel@tonic-gate 		/*
1417c478bd9Sstevel@tonic-gate 		 * Nobody has told us about this keyboard yet.
1427c478bd9Sstevel@tonic-gate 		 */
1437c478bd9Sstevel@tonic-gate 		return;
1447c478bd9Sstevel@tonic-gate 	}
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	/*
1477c478bd9Sstevel@tonic-gate 	 * Get the current state of the shiftmask
1487c478bd9Sstevel@tonic-gate 	 */
1497c478bd9Sstevel@tonic-gate 	shiftmask = lower->kbtrans_shiftmask;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	/*
1527c478bd9Sstevel@tonic-gate 	 * If the key has been released, then or in the UPMASK flag.
1537c478bd9Sstevel@tonic-gate 	 */
1547c478bd9Sstevel@tonic-gate 	if (newstate == KEY_RELEASED)
1557c478bd9Sstevel@tonic-gate 		shiftmask |= UPMASK;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	/*
1587c478bd9Sstevel@tonic-gate 	 * Based on the shiftmask, lookup the keymap entry that we should
1597c478bd9Sstevel@tonic-gate 	 * be using for this scancode.
1607c478bd9Sstevel@tonic-gate 	 */
1617c478bd9Sstevel@tonic-gate 	ke = kbtrans_find_entry(lower, shiftmask, key);
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	if (ke == NULL) {
1647c478bd9Sstevel@tonic-gate 		/*
1657c478bd9Sstevel@tonic-gate 		 * This is a gross error.  Cancel the repeat key and exit,
1667c478bd9Sstevel@tonic-gate 		 * we can not translate this scancode.
1677c478bd9Sstevel@tonic-gate 		 */
1687c478bd9Sstevel@tonic-gate 		cb->kc_cancel_repeat(lower->kbtrans_upper);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 		return;
1717c478bd9Sstevel@tonic-gate 	}
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	/*
1747c478bd9Sstevel@tonic-gate 	 * Get the key for this scancode.
1757c478bd9Sstevel@tonic-gate 	 */
1767c478bd9Sstevel@tonic-gate 	entry = *ke;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	if (entry == NONL) {
1797c478bd9Sstevel@tonic-gate 		/*
1807c478bd9Sstevel@tonic-gate 		 * NONL appears only in the Num Lock table, and indicates that
1817c478bd9Sstevel@tonic-gate 		 * this key is not affected by Num Lock.  This means we should
1827c478bd9Sstevel@tonic-gate 		 * ask for the table we would have gotten had Num Lock not been
1837c478bd9Sstevel@tonic-gate 		 * down, and translate using that table.
1847c478bd9Sstevel@tonic-gate 		 */
185*adc2b73dSToomas Soome 		ke = kbtrans_find_entry(lower, shiftmask & ~NUMLOCKMASK, key);
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 		if (ke == NULL) {
1887c478bd9Sstevel@tonic-gate 			/*
1897c478bd9Sstevel@tonic-gate 			 * This is a gross error.  Cancel the repeat key and
1907c478bd9Sstevel@tonic-gate 			 * exit, we can not translate this scancode.
1917c478bd9Sstevel@tonic-gate 			 */
1927c478bd9Sstevel@tonic-gate 			cb->kc_cancel_repeat(lower->kbtrans_upper);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 			return;
1957c478bd9Sstevel@tonic-gate 		}
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 		/*
1987c478bd9Sstevel@tonic-gate 		 * Get the new key for this scancode.
1997c478bd9Sstevel@tonic-gate 		 */
2007c478bd9Sstevel@tonic-gate 		entry = *ke;
2017c478bd9Sstevel@tonic-gate 	}
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	/*
2047c478bd9Sstevel@tonic-gate 	 * The entrytype indicates what category of key we are processing.
2057c478bd9Sstevel@tonic-gate 	 * Categories include shift keys, function keys, and numeric keypad
2067c478bd9Sstevel@tonic-gate 	 * keys.
2077c478bd9Sstevel@tonic-gate 	 */
208*adc2b73dSToomas Soome 	entrytype = KEYFLAGS(entry);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	if (entrytype == SHIFTKEYS) {
2117c478bd9Sstevel@tonic-gate 		/*
2127c478bd9Sstevel@tonic-gate 		 * Handle the state of toggle shifts specially.
2137c478bd9Sstevel@tonic-gate 		 * Ups should be ignored, and downs should be mapped to ups if
2147c478bd9Sstevel@tonic-gate 		 * that shift is currently on.
2157c478bd9Sstevel@tonic-gate 		 */
2167c478bd9Sstevel@tonic-gate 		if ((1 << (entry & 0x0F)) &
2177c478bd9Sstevel@tonic-gate 		    lower->kbtrans_keyboard->k_toggleshifts) {
218*adc2b73dSToomas Soome 			if ((1 << (entry & 0x0F)) & lower->kbtrans_togglemask) {
2197c478bd9Sstevel@tonic-gate 				newstate = KEY_RELEASED; /* toggling off */
2207c478bd9Sstevel@tonic-gate 			} else {
2217c478bd9Sstevel@tonic-gate 				newstate = KEY_PRESSED;	/* toggling on */
2227c478bd9Sstevel@tonic-gate 			}
2237c478bd9Sstevel@tonic-gate 		}
2247c478bd9Sstevel@tonic-gate 	} else {
2257c478bd9Sstevel@tonic-gate 		/*
2267c478bd9Sstevel@tonic-gate 		 * Handle Compose and floating accent key sequences
2277c478bd9Sstevel@tonic-gate 		 */
2287c478bd9Sstevel@tonic-gate 		switch (lower->kbtrans_state) {
2297c478bd9Sstevel@tonic-gate 		case COMPOSE1:
2307c478bd9Sstevel@tonic-gate 			if (newstate == KEY_RELEASED)
2317c478bd9Sstevel@tonic-gate 				return;
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 			if (entry < ASCII_SET_SIZE) {
2347c478bd9Sstevel@tonic-gate 				if (lower->kbtrans_compose_map[entry] >= 0) {
2357c478bd9Sstevel@tonic-gate 					lower->kbtrans_compose_key = entry;
2367c478bd9Sstevel@tonic-gate 					lower->kbtrans_state = COMPOSE2;
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 					return;
2397c478bd9Sstevel@tonic-gate 				}
2407c478bd9Sstevel@tonic-gate 			}
2417c478bd9Sstevel@tonic-gate 			lower->kbtrans_state = NORMAL;
2427c478bd9Sstevel@tonic-gate 			lower->kbtrans_led_state &= ~LED_COMPOSE;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 			cb->kc_setled(lower->kbtrans_upper);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 			return;
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 		case COMPOSE2:
2497c478bd9Sstevel@tonic-gate 			if (newstate == KEY_RELEASED)
2507c478bd9Sstevel@tonic-gate 				return;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 			/* next state is "normal" */
2537c478bd9Sstevel@tonic-gate 			lower->kbtrans_state = NORMAL;
2547c478bd9Sstevel@tonic-gate 			lower->kbtrans_led_state &= ~LED_COMPOSE;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 			cb->kc_setled(lower->kbtrans_upper);
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 			good_compose = kbtrans_do_compose(lower,
259*adc2b73dSToomas Soome 			    lower->kbtrans_compose_key, entry, &result);
2607c478bd9Sstevel@tonic-gate 			if (good_compose) {
2617c478bd9Sstevel@tonic-gate 				cb->kc_keypressed(lower->kbtrans_upper,
262*adc2b73dSToomas Soome 				    entrytype, key, result);
2637c478bd9Sstevel@tonic-gate 			}
2647c478bd9Sstevel@tonic-gate 			return;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 		case FLTACCENT:
2677c478bd9Sstevel@tonic-gate 			if (newstate == KEY_RELEASED)
2687c478bd9Sstevel@tonic-gate 				return;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 			/* next state is "normal" */
2717c478bd9Sstevel@tonic-gate 			lower->kbtrans_state = NORMAL;
2727c478bd9Sstevel@tonic-gate 			for (i = 0;
273*adc2b73dSToomas Soome 			    (lower->kbtrans_fltaccent_table[i].fa_entry !=
274*adc2b73dSToomas Soome 			    lower->kbtrans_fltaccent_entry) ||
2757c478bd9Sstevel@tonic-gate 			    (lower->kbtrans_fltaccent_table[i].ascii != entry);
2767c478bd9Sstevel@tonic-gate 			    i++) {
2777c478bd9Sstevel@tonic-gate 				if (lower->kbtrans_fltaccent_table[i].fa_entry
2787c478bd9Sstevel@tonic-gate 				    == 0) {
2797c478bd9Sstevel@tonic-gate 					/* Invalid second key: ignore key */
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 					return;
2827c478bd9Sstevel@tonic-gate 				}
2837c478bd9Sstevel@tonic-gate 			}
2847c478bd9Sstevel@tonic-gate 
285*adc2b73dSToomas Soome 			cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
286*adc2b73dSToomas Soome 			    lower->kbtrans_fltaccent_table[i].utf8);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 			return;
2897c478bd9Sstevel@tonic-gate 		}
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	/*
2937c478bd9Sstevel@tonic-gate 	 * If the key is going down, and it's not one of the keys that doesn't
2947c478bd9Sstevel@tonic-gate 	 * auto-repeat, set up the auto-repeat timeout.
2957c478bd9Sstevel@tonic-gate 	 *
2967c478bd9Sstevel@tonic-gate 	 * The keys that don't auto-repeat are the Compose key,
2977c478bd9Sstevel@tonic-gate 	 * the shift keys, the "bucky bit" keys, the "floating accent" keys,
2987c478bd9Sstevel@tonic-gate 	 * and the function keys when in TR_EVENT mode.
2997c478bd9Sstevel@tonic-gate 	 */
3007c478bd9Sstevel@tonic-gate 	if (newstate == KEY_PRESSED && entrytype != SHIFTKEYS &&
3017c478bd9Sstevel@tonic-gate 	    entrytype != BUCKYBITS && entrytype != FUNNY &&
3027c478bd9Sstevel@tonic-gate 	    entrytype != FA_CLASS) {
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 		if (lower->kbtrans_repeatkey != key) {
3057c478bd9Sstevel@tonic-gate 			cb->kc_cancel_repeat(lower->kbtrans_upper);
3067c478bd9Sstevel@tonic-gate 			cb->kc_setup_repeat(lower->kbtrans_upper, entrytype,
307*adc2b73dSToomas Soome 			    key);
3087c478bd9Sstevel@tonic-gate 		}
3097c478bd9Sstevel@tonic-gate 		/* key going up */
3107c478bd9Sstevel@tonic-gate 	} else if (key == lower->kbtrans_repeatkey) {
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 		cb->kc_cancel_repeat(lower->kbtrans_upper);
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	if (newstate == KEY_RELEASED) {
3167c478bd9Sstevel@tonic-gate 		cb->kc_keyreleased(lower->kbtrans_upper, key);
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	/*
3207c478bd9Sstevel@tonic-gate 	 * We assume here that keys other than shift keys and bucky keys have
3217c478bd9Sstevel@tonic-gate 	 * entries in the "up" table that cause nothing to be done, and thus we
3227c478bd9Sstevel@tonic-gate 	 * don't have to check for newstate == KEY_RELEASED.
3237c478bd9Sstevel@tonic-gate 	 */
3247c478bd9Sstevel@tonic-gate 	switch (entrytype) {
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	case 0x0:		/* regular key */
3277c478bd9Sstevel@tonic-gate 		cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
328*adc2b73dSToomas Soome 		    SPECIAL(lower->kbtrans_buckybits, entry));
3297c478bd9Sstevel@tonic-gate 		break;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	case SHIFTKEYS: {
3327c478bd9Sstevel@tonic-gate 		uint_t shiftbit = 1 << (entry & 0x0F);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 		/* Modify toggle state (see toggle processing above) */
3357c478bd9Sstevel@tonic-gate 		if (shiftbit & lower->kbtrans_keyboard->k_toggleshifts) {
3367c478bd9Sstevel@tonic-gate 			if (newstate == KEY_RELEASED) {
3377c478bd9Sstevel@tonic-gate 				if (shiftbit == CAPSMASK) {
3387c478bd9Sstevel@tonic-gate 					lower->kbtrans_led_state &=
339*adc2b73dSToomas Soome 					    ~LED_CAPS_LOCK;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 					cb->kc_setled(lower->kbtrans_upper);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 				} else if (shiftbit == NUMLOCKMASK) {
3447c478bd9Sstevel@tonic-gate 					lower->kbtrans_led_state &=
345*adc2b73dSToomas Soome 					    ~LED_NUM_LOCK;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 					cb->kc_setled(lower->kbtrans_upper);
3487c478bd9Sstevel@tonic-gate 				}
3497c478bd9Sstevel@tonic-gate 				lower->kbtrans_togglemask &= ~shiftbit;
3507c478bd9Sstevel@tonic-gate 			} else {
3517c478bd9Sstevel@tonic-gate 				if (shiftbit == CAPSMASK) {
3527c478bd9Sstevel@tonic-gate 					lower->kbtrans_led_state |=
353*adc2b73dSToomas Soome 					    LED_CAPS_LOCK;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 					cb->kc_setled(lower->kbtrans_upper);
3567c478bd9Sstevel@tonic-gate 				} else if (shiftbit == NUMLOCKMASK) {
3577c478bd9Sstevel@tonic-gate 					lower->kbtrans_led_state |=
358*adc2b73dSToomas Soome 					    LED_NUM_LOCK;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 					cb->kc_setled(lower->kbtrans_upper);
3617c478bd9Sstevel@tonic-gate 				}
3627c478bd9Sstevel@tonic-gate 				lower->kbtrans_togglemask |= shiftbit;
3637c478bd9Sstevel@tonic-gate 			}
3647c478bd9Sstevel@tonic-gate 		}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 		if (newstate == KEY_RELEASED)
3677c478bd9Sstevel@tonic-gate 			lower->kbtrans_shiftmask &= ~shiftbit;
3687c478bd9Sstevel@tonic-gate 		else
3697c478bd9Sstevel@tonic-gate 			lower->kbtrans_shiftmask |= shiftbit;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 		if (newstate == KEY_PRESSED) {
3727c478bd9Sstevel@tonic-gate 			cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
373*adc2b73dSToomas Soome 			    entry);
3747c478bd9Sstevel@tonic-gate 		}
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		break;
3777c478bd9Sstevel@tonic-gate 		}
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	case BUCKYBITS:
380*adc2b73dSToomas Soome 		lower->kbtrans_buckybits ^= 1 << (entry & 0x0F);
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 		if (newstate == KEY_PRESSED) {
3837c478bd9Sstevel@tonic-gate 			cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
384*adc2b73dSToomas Soome 			    entry);
3857c478bd9Sstevel@tonic-gate 		}
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 		break;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	case FUNNY:
3907c478bd9Sstevel@tonic-gate 		switch (entry) {
3917c478bd9Sstevel@tonic-gate 		case NOP:
3927c478bd9Sstevel@tonic-gate 			break;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 		case IDLE:
3957c478bd9Sstevel@tonic-gate 			/* Fall thru into RESET code */
3967c478bd9Sstevel@tonic-gate 			/* FALLTHRU */
3977c478bd9Sstevel@tonic-gate 		case RESET:
3987c478bd9Sstevel@tonic-gate 		case ERROR:
3997c478bd9Sstevel@tonic-gate 			lower->kbtrans_shiftmask &=
400*adc2b73dSToomas Soome 			    lower->kbtrans_keyboard->k_idleshifts;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 			lower->kbtrans_shiftmask |=
403*adc2b73dSToomas Soome 			    lower->kbtrans_togglemask;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 			lower->kbtrans_buckybits &=
406*adc2b73dSToomas Soome 			    lower->kbtrans_keyboard->k_idlebuckys;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 			cb->kc_cancel_repeat(lower->kbtrans_upper);
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 			cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
411*adc2b73dSToomas Soome 			    entry);
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 			break;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 		case COMPOSE:
4177c478bd9Sstevel@tonic-gate 			lower->kbtrans_state = COMPOSE1;
4187c478bd9Sstevel@tonic-gate 			lower->kbtrans_led_state |= LED_COMPOSE;
4197c478bd9Sstevel@tonic-gate 			cb->kc_setled(lower->kbtrans_upper);
4207c478bd9Sstevel@tonic-gate 			break;
4217c478bd9Sstevel@tonic-gate 		/*
4227c478bd9Sstevel@tonic-gate 		 * Remember when adding new entries that,
4237c478bd9Sstevel@tonic-gate 		 * if they should NOT auto-repeat,
4247c478bd9Sstevel@tonic-gate 		 * they should be put into the IF statement
4257c478bd9Sstevel@tonic-gate 		 * just above this switch block.
4267c478bd9Sstevel@tonic-gate 		 */
4277c478bd9Sstevel@tonic-gate 		default:
4287c478bd9Sstevel@tonic-gate 			/* Ignore it */
4297c478bd9Sstevel@tonic-gate 			break;
4307c478bd9Sstevel@tonic-gate 		}
4317c478bd9Sstevel@tonic-gate 		break;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	case FA_CLASS:
4347c478bd9Sstevel@tonic-gate 		if (lower->kbtrans_state == NORMAL) {
4357c478bd9Sstevel@tonic-gate 			lower->kbtrans_fltaccent_entry = entry;
4367c478bd9Sstevel@tonic-gate 			lower->kbtrans_state = FLTACCENT;
4377c478bd9Sstevel@tonic-gate 		}
4387c478bd9Sstevel@tonic-gate 		break;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	case STRING:
4417c478bd9Sstevel@tonic-gate 		cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 		break;
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	case FUNCKEYS:
4467c478bd9Sstevel@tonic-gate 		cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry);
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 		break;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	/*
4517c478bd9Sstevel@tonic-gate 	 * Remember when adding new entries that,
4527c478bd9Sstevel@tonic-gate 	 * if they should NOT auto-repeat,
4537c478bd9Sstevel@tonic-gate 	 * they should be put into the IF statement
4547c478bd9Sstevel@tonic-gate 	 * just above this switch block.
4557c478bd9Sstevel@tonic-gate 	 */
4567c478bd9Sstevel@tonic-gate 	case PADKEYS:
4577c478bd9Sstevel@tonic-gate 		cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 		break;
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate /*
4647c478bd9Sstevel@tonic-gate  * kbtrans_do_compose:
4657c478bd9Sstevel@tonic-gate  *	Given a two key compose sequence, lookup the iso equivalent and put
466*adc2b73dSToomas Soome  *	the result in the result_ptr.
4677c478bd9Sstevel@tonic-gate  */
4687c478bd9Sstevel@tonic-gate static boolean_t
kbtrans_do_compose(struct kbtrans_lower * lower,keymap_entry_t first_entry,keymap_entry_t second_entry,keymap_entry_t * result_ptr)469*adc2b73dSToomas Soome kbtrans_do_compose(struct kbtrans_lower *lower, keymap_entry_t first_entry,
470*adc2b73dSToomas Soome     keymap_entry_t second_entry, keymap_entry_t *result_ptr)
4717c478bd9Sstevel@tonic-gate {
4727c478bd9Sstevel@tonic-gate 	struct compose_sequence_t *ptr;
473*adc2b73dSToomas Soome 	keymap_entry_t tmp;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	/*
4767c478bd9Sstevel@tonic-gate 	 * Validate the second keystroke.
4777c478bd9Sstevel@tonic-gate 	 */
4787c478bd9Sstevel@tonic-gate 	if (second_entry >= ASCII_SET_SIZE)
4797c478bd9Sstevel@tonic-gate 		return (B_FALSE);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	if (lower->kbtrans_compose_map[second_entry] < 0)
4827c478bd9Sstevel@tonic-gate 		return (B_FALSE);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	/*
4857c478bd9Sstevel@tonic-gate 	 * Get them in code order, rather than press order.
4867c478bd9Sstevel@tonic-gate 	 */
4877c478bd9Sstevel@tonic-gate 	if (first_entry > second_entry) {
4887c478bd9Sstevel@tonic-gate 		tmp = first_entry;
4897c478bd9Sstevel@tonic-gate 		first_entry = second_entry;
4907c478bd9Sstevel@tonic-gate 		second_entry = tmp;
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	ptr = lower->kbtrans_compose_table +
494*adc2b73dSToomas Soome 	    lower->kbtrans_compose_map[first_entry];
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	while (ptr->first == first_entry) {
4977c478bd9Sstevel@tonic-gate 		if (ptr->second == second_entry) {
498*adc2b73dSToomas Soome 			*result_ptr = ptr->utf8;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 			return (B_TRUE);
5017c478bd9Sstevel@tonic-gate 		}
5027c478bd9Sstevel@tonic-gate 		ptr++;
5037c478bd9Sstevel@tonic-gate 	}
5047c478bd9Sstevel@tonic-gate 	return (B_FALSE);
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate /*
5097c478bd9Sstevel@tonic-gate  * kbtrans_find_entry:
5107c478bd9Sstevel@tonic-gate  * 	This routine finds the entry corresponding to the current shift
5117c478bd9Sstevel@tonic-gate  * 	state and keycode.
5127c478bd9Sstevel@tonic-gate  */
513*adc2b73dSToomas Soome keymap_entry_t *
kbtrans_find_entry(struct kbtrans_lower * lower,uint_t mask,kbtrans_key_t key_station)514*adc2b73dSToomas Soome kbtrans_find_entry(struct kbtrans_lower *lower, uint_t mask,
515*adc2b73dSToomas Soome     kbtrans_key_t key_station)
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate 	register struct keyboard *kp;
5187c478bd9Sstevel@tonic-gate 	keymap_entry_t *km;
5197c478bd9Sstevel@tonic-gate 	struct exception_map *ex;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	kp = lower->kbtrans_keyboard;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	if (kp == NULL)
5247c478bd9Sstevel@tonic-gate 		return (NULL);
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	if (key_station < 0 || key_station >= kp->k_keymap_size)
5277c478bd9Sstevel@tonic-gate 		return (NULL);
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	ex = kp->k_except;
5307c478bd9Sstevel@tonic-gate 	if (ex != NULL) {
5317c478bd9Sstevel@tonic-gate 		for (; ex->exc_care != 0; ex++) {
5327c478bd9Sstevel@tonic-gate 			if ((mask & ex->exc_care) == ex->exc_mask &&
5337c478bd9Sstevel@tonic-gate 			    key_station == ex->exc_key)
5347c478bd9Sstevel@tonic-gate 				return (&ex->exc_entry);
5357c478bd9Sstevel@tonic-gate 		}
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	if (mask & UPMASK)
5397c478bd9Sstevel@tonic-gate 		km = kp->k_up;
5407c478bd9Sstevel@tonic-gate 	else if (mask & NUMLOCKMASK)
5417c478bd9Sstevel@tonic-gate 		km = kp->k_numlock;
5427c478bd9Sstevel@tonic-gate 	else if (mask & CTRLMASK)
5437c478bd9Sstevel@tonic-gate 		km = kp->k_control;
5447c478bd9Sstevel@tonic-gate 	else if (mask & ALTGRAPHMASK)
5457c478bd9Sstevel@tonic-gate 		km = kp->k_altgraph;
5467c478bd9Sstevel@tonic-gate 	else if (mask & SHIFTMASK)
5477c478bd9Sstevel@tonic-gate 		km = kp->k_shifted;
5487c478bd9Sstevel@tonic-gate 	else if (mask & CAPSMASK)
5497c478bd9Sstevel@tonic-gate 		km = kp->k_caps;
5507c478bd9Sstevel@tonic-gate 	else km = kp->k_normal;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	return (&km[key_station]);
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate #ifdef DEBUG
5567c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5577c478bd9Sstevel@tonic-gate void
kbtrans_dprintf(void * un,const char * fmt,...)5587c478bd9Sstevel@tonic-gate kbtrans_dprintf(void *un, const char *fmt, ...)
5597c478bd9Sstevel@tonic-gate {
5607c478bd9Sstevel@tonic-gate 	char buf[256];
5617c478bd9Sstevel@tonic-gate 	va_list ap;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
5647c478bd9Sstevel@tonic-gate 	(void) vsprintf(buf, fmt, ap);
5657c478bd9Sstevel@tonic-gate 	va_end(ap);
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "kbtrans: %s", buf);
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate #endif
570