4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Generic keyboard support: translation
30 * This module is project private. Please see PSARC/1998/176 and
31 * PSARC/1998/026 for references to the kbtrans module.
33 * It is believed that it is safe to call these functions within debugger mode
34 * except kbtrans_dprintf. Debugger mode is a single threaded mode where most
35 * kernel services are not available, including memory allocation. Debugger
36 * mode is for kmdb and OBP debugging, where the debugger calls back into the
37 * kernel to obtain console input.
39 * Please be _very_ careful about what external functions you call.
42 #define KEYMAP_SIZE_VARIABLE
44 #include <sys/types.h>
47 #include <sys/sunddi.h>
50 #include <sys/cmn_err.h>
51 #include <sys/modctl.h>
53 #include <sys/vuid_event.h>
54 #include <sys/consdev.h>
55 #include <sys/kbtrans.h>
56 #include <sys/errno.h>
57 #include <sys/promif.h>
58 #include <sys/varargs.h>
59 #include "kbtrans_lower.h"
62 * Internal Function Prototypes
64 static boolean_t
kbtrans_do_compose(struct kbtrans_lower
*, keymap_entry_t
,
65 keymap_entry_t
, keymap_entry_t
*);
66 static void kbtrans_translate(struct kbtrans_lower
*,
67 struct keyboard_callback
*, kbtrans_key_t
, enum keystate
);
72 * lower - state information used by the calling driver
73 * this parameter is passed back to the callback routines.
75 * state - KEY_PRESSED / KEY_RELEASED
77 * This routine checks to see if there is a raw callback, and calls it
78 * if it exists. If there is no raw callback, the key is translated.
79 * The raw callback allows the driver that called the translation module
80 * to be passed untranslated scancodes.
83 kbtrans_processkey(struct kbtrans_lower
*lower
,
84 struct keyboard_callback
*cb
, kbtrans_key_t key
, enum keystate state
)
86 DPRINTF(PRINT_L0
, PRINT_MASK_ALL
, (lower
, "kbtrans_processkey: "
87 "newstate=%d key=%d", state
, key
));
90 * If there is a raw routine, then call it and return.
92 if (cb
->kc_keypressed_raw
!= NULL
) {
94 if (state
== KEY_PRESSED
) {
96 cb
->kc_keypressed_raw(lower
->kbtrans_upper
, key
);
99 cb
->kc_keyreleased_raw(lower
->kbtrans_upper
, key
);
106 * translate the scancode into a key.
108 kbtrans_translate(lower
, cb
, key
, state
);
115 * lower - state information used by the calling driver
116 * this parameter is passed back to the callback routines.
118 * state - KEY_PRESSED / KEY_RELEASED
120 * Called to process key events if we are in TR_ASCII or TR_EVENT
121 * (sunview) mode. This routine will call the appropriate translation_callback
122 * for the character when it is done translating it.
125 kbtrans_translate(struct kbtrans_lower
*lower
, struct keyboard_callback
*cb
,
126 kbtrans_key_t key
, enum keystate newstate
)
129 register keymap_entry_t entry
;
130 register unsigned entrytype
;
131 keymap_entry_t result
;
134 boolean_t good_compose
;
136 DPRINTF(PRINT_L0
, PRINT_MASK_ALL
, (lower
, "KEY TRANSLATE "
137 "newstate=0x%x key=0x%x\n", newstate
, key
));
139 if (lower
->kbtrans_keyboard
== NULL
) {
141 * Nobody has told us about this keyboard yet.
147 * Get the current state of the shiftmask
149 shiftmask
= lower
->kbtrans_shiftmask
;
152 * If the key has been released, then or in the UPMASK flag.
154 if (newstate
== KEY_RELEASED
)
158 * Based on the shiftmask, lookup the keymap entry that we should
159 * be using for this scancode.
161 ke
= kbtrans_find_entry(lower
, shiftmask
, key
);
165 * This is a gross error. Cancel the repeat key and exit,
166 * we can not translate this scancode.
168 cb
->kc_cancel_repeat(lower
->kbtrans_upper
);
174 * Get the key for this scancode.
180 * NONL appears only in the Num Lock table, and indicates that
181 * this key is not affected by Num Lock. This means we should
182 * ask for the table we would have gotten had Num Lock not been
183 * down, and translate using that table.
185 ke
= kbtrans_find_entry(lower
, shiftmask
& ~NUMLOCKMASK
, key
);
189 * This is a gross error. Cancel the repeat key and
190 * exit, we can not translate this scancode.
192 cb
->kc_cancel_repeat(lower
->kbtrans_upper
);
198 * Get the new key for this scancode.
204 * The entrytype indicates what category of key we are processing.
205 * Categories include shift keys, function keys, and numeric keypad
208 entrytype
= KEYFLAGS(entry
);
210 if (entrytype
== SHIFTKEYS
) {
212 * Handle the state of toggle shifts specially.
213 * Ups should be ignored, and downs should be mapped to ups if
214 * that shift is currently on.
216 if ((1 << (entry
& 0x0F)) &
217 lower
->kbtrans_keyboard
->k_toggleshifts
) {
218 if ((1 << (entry
& 0x0F)) & lower
->kbtrans_togglemask
) {
219 newstate
= KEY_RELEASED
; /* toggling off */
221 newstate
= KEY_PRESSED
; /* toggling on */
226 * Handle Compose and floating accent key sequences
228 switch (lower
->kbtrans_state
) {
230 if (newstate
== KEY_RELEASED
)
233 if (entry
< ASCII_SET_SIZE
) {
234 if (lower
->kbtrans_compose_map
[entry
] >= 0) {
235 lower
->kbtrans_compose_key
= entry
;
236 lower
->kbtrans_state
= COMPOSE2
;
241 lower
->kbtrans_state
= NORMAL
;
242 lower
->kbtrans_led_state
&= ~LED_COMPOSE
;
244 cb
->kc_setled(lower
->kbtrans_upper
);
249 if (newstate
== KEY_RELEASED
)
252 /* next state is "normal" */
253 lower
->kbtrans_state
= NORMAL
;
254 lower
->kbtrans_led_state
&= ~LED_COMPOSE
;
256 cb
->kc_setled(lower
->kbtrans_upper
);
258 good_compose
= kbtrans_do_compose(lower
,
259 lower
->kbtrans_compose_key
, entry
, &result
);
261 cb
->kc_keypressed(lower
->kbtrans_upper
,
262 entrytype
, key
, result
);
267 if (newstate
== KEY_RELEASED
)
270 /* next state is "normal" */
271 lower
->kbtrans_state
= NORMAL
;
273 (lower
->kbtrans_fltaccent_table
[i
].fa_entry
!=
274 lower
->kbtrans_fltaccent_entry
) ||
275 (lower
->kbtrans_fltaccent_table
[i
].ascii
!= entry
);
277 if (lower
->kbtrans_fltaccent_table
[i
].fa_entry
279 /* Invalid second key: ignore key */
285 cb
->kc_keypressed(lower
->kbtrans_upper
, entrytype
, key
,
286 lower
->kbtrans_fltaccent_table
[i
].utf8
);
293 * If the key is going down, and it's not one of the keys that doesn't
294 * auto-repeat, set up the auto-repeat timeout.
296 * The keys that don't auto-repeat are the Compose key,
297 * the shift keys, the "bucky bit" keys, the "floating accent" keys,
298 * and the function keys when in TR_EVENT mode.
300 if (newstate
== KEY_PRESSED
&& entrytype
!= SHIFTKEYS
&&
301 entrytype
!= BUCKYBITS
&& entrytype
!= FUNNY
&&
302 entrytype
!= FA_CLASS
) {
304 if (lower
->kbtrans_repeatkey
!= key
) {
305 cb
->kc_cancel_repeat(lower
->kbtrans_upper
);
306 cb
->kc_setup_repeat(lower
->kbtrans_upper
, entrytype
,
310 } else if (key
== lower
->kbtrans_repeatkey
) {
312 cb
->kc_cancel_repeat(lower
->kbtrans_upper
);
315 if (newstate
== KEY_RELEASED
) {
316 cb
->kc_keyreleased(lower
->kbtrans_upper
, key
);
320 * We assume here that keys other than shift keys and bucky keys have
321 * entries in the "up" table that cause nothing to be done, and thus we
322 * don't have to check for newstate == KEY_RELEASED.
326 case 0x0: /* regular key */
327 cb
->kc_keypressed(lower
->kbtrans_upper
, entrytype
, key
,
328 SPECIAL(lower
->kbtrans_buckybits
, entry
));
332 uint_t shiftbit
= 1 << (entry
& 0x0F);
334 /* Modify toggle state (see toggle processing above) */
335 if (shiftbit
& lower
->kbtrans_keyboard
->k_toggleshifts
) {
336 if (newstate
== KEY_RELEASED
) {
337 if (shiftbit
== CAPSMASK
) {
338 lower
->kbtrans_led_state
&=
341 cb
->kc_setled(lower
->kbtrans_upper
);
343 } else if (shiftbit
== NUMLOCKMASK
) {
344 lower
->kbtrans_led_state
&=
347 cb
->kc_setled(lower
->kbtrans_upper
);
349 lower
->kbtrans_togglemask
&= ~shiftbit
;
351 if (shiftbit
== CAPSMASK
) {
352 lower
->kbtrans_led_state
|=
355 cb
->kc_setled(lower
->kbtrans_upper
);
356 } else if (shiftbit
== NUMLOCKMASK
) {
357 lower
->kbtrans_led_state
|=
360 cb
->kc_setled(lower
->kbtrans_upper
);
362 lower
->kbtrans_togglemask
|= shiftbit
;
366 if (newstate
== KEY_RELEASED
)
367 lower
->kbtrans_shiftmask
&= ~shiftbit
;
369 lower
->kbtrans_shiftmask
|= shiftbit
;
371 if (newstate
== KEY_PRESSED
) {
372 cb
->kc_keypressed(lower
->kbtrans_upper
, entrytype
, key
,
380 lower
->kbtrans_buckybits
^= 1 << (entry
& 0x0F);
382 if (newstate
== KEY_PRESSED
) {
383 cb
->kc_keypressed(lower
->kbtrans_upper
, entrytype
, key
,
395 /* Fall thru into RESET code */
399 lower
->kbtrans_shiftmask
&=
400 lower
->kbtrans_keyboard
->k_idleshifts
;
402 lower
->kbtrans_shiftmask
|=
403 lower
->kbtrans_togglemask
;
405 lower
->kbtrans_buckybits
&=
406 lower
->kbtrans_keyboard
->k_idlebuckys
;
408 cb
->kc_cancel_repeat(lower
->kbtrans_upper
);
410 cb
->kc_keypressed(lower
->kbtrans_upper
, entrytype
, key
,
417 lower
->kbtrans_state
= COMPOSE1
;
418 lower
->kbtrans_led_state
|= LED_COMPOSE
;
419 cb
->kc_setled(lower
->kbtrans_upper
);
422 * Remember when adding new entries that,
423 * if they should NOT auto-repeat,
424 * they should be put into the IF statement
425 * just above this switch block.
434 if (lower
->kbtrans_state
== NORMAL
) {
435 lower
->kbtrans_fltaccent_entry
= entry
;
436 lower
->kbtrans_state
= FLTACCENT
;
441 cb
->kc_keypressed(lower
->kbtrans_upper
, entrytype
, key
, entry
);
446 cb
->kc_keypressed(lower
->kbtrans_upper
, entrytype
, key
, entry
);
451 * Remember when adding new entries that,
452 * if they should NOT auto-repeat,
453 * they should be put into the IF statement
454 * just above this switch block.
457 cb
->kc_keypressed(lower
->kbtrans_upper
, entrytype
, key
, entry
);
464 * kbtrans_do_compose:
465 * Given a two key compose sequence, lookup the iso equivalent and put
466 * the result in the result_ptr.
469 kbtrans_do_compose(struct kbtrans_lower
*lower
, keymap_entry_t first_entry
,
470 keymap_entry_t second_entry
, keymap_entry_t
*result_ptr
)
472 struct compose_sequence_t
*ptr
;
476 * Validate the second keystroke.
478 if (second_entry
>= ASCII_SET_SIZE
)
481 if (lower
->kbtrans_compose_map
[second_entry
] < 0)
485 * Get them in code order, rather than press order.
487 if (first_entry
> second_entry
) {
489 first_entry
= second_entry
;
493 ptr
= lower
->kbtrans_compose_table
+
494 lower
->kbtrans_compose_map
[first_entry
];
496 while (ptr
->first
== first_entry
) {
497 if (ptr
->second
== second_entry
) {
498 *result_ptr
= ptr
->utf8
;
509 * kbtrans_find_entry:
510 * This routine finds the entry corresponding to the current shift
514 kbtrans_find_entry(struct kbtrans_lower
*lower
, uint_t mask
,
515 kbtrans_key_t key_station
)
517 register struct keyboard
*kp
;
519 struct exception_map
*ex
;
521 kp
= lower
->kbtrans_keyboard
;
526 if (key_station
< 0 || key_station
>= kp
->k_keymap_size
)
531 for (; ex
->exc_care
!= 0; ex
++) {
532 if ((mask
& ex
->exc_care
) == ex
->exc_mask
&&
533 key_station
== ex
->exc_key
)
534 return (&ex
->exc_entry
);
540 else if (mask
& NUMLOCKMASK
)
542 else if (mask
& CTRLMASK
)
544 else if (mask
& ALTGRAPHMASK
)
546 else if (mask
& SHIFTMASK
)
548 else if (mask
& CAPSMASK
)
550 else km
= kp
->k_normal
;
552 return (&km
[key_station
]);
558 kbtrans_dprintf(void *un
, const char *fmt
, ...)
564 (void) vsprintf(buf
, fmt
, ap
);
567 cmn_err(CE_CONT
, "kbtrans: %s", buf
);