1 /*
2 * CDDL HEADER START
3 *
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
7 * with the License.
8 *
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.
13 *
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]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Generic keyboard support: translation
29 *
30 * This module is project private. Please see PSARC/1998/176 and
31 * PSARC/1998/026 for references to the kbtrans module.
32 *
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.
38 *
39 * Please be _very_ careful about what external functions you call.
40 */
41
42 #define KEYMAP_SIZE_VARIABLE
43
44 #include <sys/types.h>
45 #include <sys/cred.h>
46 #include <sys/ddi.h>
47 #include <sys/sunddi.h>
48 #include <sys/kmem.h>
49 #include <sys/kbd.h>
50 #include <sys/cmn_err.h>
51 #include <sys/modctl.h>
52 #include <sys/kbio.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"
60
61 /*
62 * Internal Function Prototypes
63 */
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);
68
69 /*
70 * kbtrans_processkey:
71 *
72 * lower - state information used by the calling driver
73 * this parameter is passed back to the callback routines.
74 * key - scancode
75 * state - KEY_PRESSED / KEY_RELEASED
76 *
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.
81 */
82 void
kbtrans_processkey(struct kbtrans_lower * lower,struct keyboard_callback * cb,kbtrans_key_t key,enum keystate state)83 kbtrans_processkey(struct kbtrans_lower *lower,
84 struct keyboard_callback *cb, kbtrans_key_t key, enum keystate state)
85 {
86 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (lower, "kbtrans_processkey: "
87 "newstate=%d key=%d", state, key));
88
89 /*
90 * If there is a raw routine, then call it and return.
91 */
92 if (cb->kc_keypressed_raw != NULL) {
93
94 if (state == KEY_PRESSED) {
95
96 cb->kc_keypressed_raw(lower->kbtrans_upper, key);
97 } else {
98
99 cb->kc_keyreleased_raw(lower->kbtrans_upper, key);
100 }
101
102 return;
103 }
104
105 /*
106 * translate the scancode into a key.
107 */
108 kbtrans_translate(lower, cb, key, state);
109 }
110
111
112 /*
113 * kbtrans_translate:
114 *
115 * lower - state information used by the calling driver
116 * this parameter is passed back to the callback routines.
117 * key - scan code
118 * state - KEY_PRESSED / KEY_RELEASED
119 *
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.
123 */
124 static void
kbtrans_translate(struct kbtrans_lower * lower,struct keyboard_callback * cb,kbtrans_key_t key,enum keystate newstate)125 kbtrans_translate(struct kbtrans_lower *lower, struct keyboard_callback *cb,
126 kbtrans_key_t key, enum keystate newstate)
127 {
128 unsigned shiftmask;
129 register keymap_entry_t entry;
130 register unsigned entrytype;
131 keymap_entry_t result;
132 keymap_entry_t *ke;
133 int i;
134 boolean_t good_compose;
135
136 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (lower, "KEY TRANSLATE "
137 "newstate=0x%x key=0x%x\n", newstate, key));
138
139 if (lower->kbtrans_keyboard == NULL) {
140 /*
141 * Nobody has told us about this keyboard yet.
142 */
143 return;
144 }
145
146 /*
147 * Get the current state of the shiftmask
148 */
149 shiftmask = lower->kbtrans_shiftmask;
150
151 /*
152 * If the key has been released, then or in the UPMASK flag.
153 */
154 if (newstate == KEY_RELEASED)
155 shiftmask |= UPMASK;
156
157 /*
158 * Based on the shiftmask, lookup the keymap entry that we should
159 * be using for this scancode.
160 */
161 ke = kbtrans_find_entry(lower, shiftmask, key);
162
163 if (ke == NULL) {
164 /*
165 * This is a gross error. Cancel the repeat key and exit,
166 * we can not translate this scancode.
167 */
168 cb->kc_cancel_repeat(lower->kbtrans_upper);
169
170 return;
171 }
172
173 /*
174 * Get the key for this scancode.
175 */
176 entry = *ke;
177
178 if (entry == NONL) {
179 /*
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.
184 */
185 ke = kbtrans_find_entry(lower, shiftmask & ~NUMLOCKMASK, key);
186
187 if (ke == NULL) {
188 /*
189 * This is a gross error. Cancel the repeat key and
190 * exit, we can not translate this scancode.
191 */
192 cb->kc_cancel_repeat(lower->kbtrans_upper);
193
194 return;
195 }
196
197 /*
198 * Get the new key for this scancode.
199 */
200 entry = *ke;
201 }
202
203 /*
204 * The entrytype indicates what category of key we are processing.
205 * Categories include shift keys, function keys, and numeric keypad
206 * keys.
207 */
208 entrytype = KEYFLAGS(entry);
209
210 if (entrytype == SHIFTKEYS) {
211 /*
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.
215 */
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 */
220 } else {
221 newstate = KEY_PRESSED; /* toggling on */
222 }
223 }
224 } else {
225 /*
226 * Handle Compose and floating accent key sequences
227 */
228 switch (lower->kbtrans_state) {
229 case COMPOSE1:
230 if (newstate == KEY_RELEASED)
231 return;
232
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;
237
238 return;
239 }
240 }
241 lower->kbtrans_state = NORMAL;
242 lower->kbtrans_led_state &= ~LED_COMPOSE;
243
244 cb->kc_setled(lower->kbtrans_upper);
245
246 return;
247
248 case COMPOSE2:
249 if (newstate == KEY_RELEASED)
250 return;
251
252 /* next state is "normal" */
253 lower->kbtrans_state = NORMAL;
254 lower->kbtrans_led_state &= ~LED_COMPOSE;
255
256 cb->kc_setled(lower->kbtrans_upper);
257
258 good_compose = kbtrans_do_compose(lower,
259 lower->kbtrans_compose_key, entry, &result);
260 if (good_compose) {
261 cb->kc_keypressed(lower->kbtrans_upper,
262 entrytype, key, result);
263 }
264 return;
265
266 case FLTACCENT:
267 if (newstate == KEY_RELEASED)
268 return;
269
270 /* next state is "normal" */
271 lower->kbtrans_state = NORMAL;
272 for (i = 0;
273 (lower->kbtrans_fltaccent_table[i].fa_entry !=
274 lower->kbtrans_fltaccent_entry) ||
275 (lower->kbtrans_fltaccent_table[i].ascii != entry);
276 i++) {
277 if (lower->kbtrans_fltaccent_table[i].fa_entry
278 == 0) {
279 /* Invalid second key: ignore key */
280
281 return;
282 }
283 }
284
285 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
286 lower->kbtrans_fltaccent_table[i].utf8);
287
288 return;
289 }
290 }
291
292 /*
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.
295 *
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.
299 */
300 if (newstate == KEY_PRESSED && entrytype != SHIFTKEYS &&
301 entrytype != BUCKYBITS && entrytype != FUNNY &&
302 entrytype != FA_CLASS) {
303
304 if (lower->kbtrans_repeatkey != key) {
305 cb->kc_cancel_repeat(lower->kbtrans_upper);
306 cb->kc_setup_repeat(lower->kbtrans_upper, entrytype,
307 key);
308 }
309 /* key going up */
310 } else if (key == lower->kbtrans_repeatkey) {
311
312 cb->kc_cancel_repeat(lower->kbtrans_upper);
313 }
314
315 if (newstate == KEY_RELEASED) {
316 cb->kc_keyreleased(lower->kbtrans_upper, key);
317 }
318
319 /*
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.
323 */
324 switch (entrytype) {
325
326 case 0x0: /* regular key */
327 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
328 SPECIAL(lower->kbtrans_buckybits, entry));
329 break;
330
331 case SHIFTKEYS: {
332 uint_t shiftbit = 1 << (entry & 0x0F);
333
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 &=
339 ~LED_CAPS_LOCK;
340
341 cb->kc_setled(lower->kbtrans_upper);
342
343 } else if (shiftbit == NUMLOCKMASK) {
344 lower->kbtrans_led_state &=
345 ~LED_NUM_LOCK;
346
347 cb->kc_setled(lower->kbtrans_upper);
348 }
349 lower->kbtrans_togglemask &= ~shiftbit;
350 } else {
351 if (shiftbit == CAPSMASK) {
352 lower->kbtrans_led_state |=
353 LED_CAPS_LOCK;
354
355 cb->kc_setled(lower->kbtrans_upper);
356 } else if (shiftbit == NUMLOCKMASK) {
357 lower->kbtrans_led_state |=
358 LED_NUM_LOCK;
359
360 cb->kc_setled(lower->kbtrans_upper);
361 }
362 lower->kbtrans_togglemask |= shiftbit;
363 }
364 }
365
366 if (newstate == KEY_RELEASED)
367 lower->kbtrans_shiftmask &= ~shiftbit;
368 else
369 lower->kbtrans_shiftmask |= shiftbit;
370
371 if (newstate == KEY_PRESSED) {
372 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
373 entry);
374 }
375
376 break;
377 }
378
379 case BUCKYBITS:
380 lower->kbtrans_buckybits ^= 1 << (entry & 0x0F);
381
382 if (newstate == KEY_PRESSED) {
383 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
384 entry);
385 }
386
387 break;
388
389 case FUNNY:
390 switch (entry) {
391 case NOP:
392 break;
393
394 case IDLE:
395 /* Fall thru into RESET code */
396 /* FALLTHRU */
397 case RESET:
398 case ERROR:
399 lower->kbtrans_shiftmask &=
400 lower->kbtrans_keyboard->k_idleshifts;
401
402 lower->kbtrans_shiftmask |=
403 lower->kbtrans_togglemask;
404
405 lower->kbtrans_buckybits &=
406 lower->kbtrans_keyboard->k_idlebuckys;
407
408 cb->kc_cancel_repeat(lower->kbtrans_upper);
409
410 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
411 entry);
412
413 break;
414
415
416 case COMPOSE:
417 lower->kbtrans_state = COMPOSE1;
418 lower->kbtrans_led_state |= LED_COMPOSE;
419 cb->kc_setled(lower->kbtrans_upper);
420 break;
421 /*
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.
426 */
427 default:
428 /* Ignore it */
429 break;
430 }
431 break;
432
433 case FA_CLASS:
434 if (lower->kbtrans_state == NORMAL) {
435 lower->kbtrans_fltaccent_entry = entry;
436 lower->kbtrans_state = FLTACCENT;
437 }
438 break;
439
440 case STRING:
441 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry);
442
443 break;
444
445 case FUNCKEYS:
446 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry);
447
448 break;
449
450 /*
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.
455 */
456 case PADKEYS:
457 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry);
458
459 break;
460 }
461 }
462
463 /*
464 * kbtrans_do_compose:
465 * Given a two key compose sequence, lookup the iso equivalent and put
466 * the result in the result_ptr.
467 */
468 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 kbtrans_do_compose(struct kbtrans_lower *lower, keymap_entry_t first_entry,
470 keymap_entry_t second_entry, keymap_entry_t *result_ptr)
471 {
472 struct compose_sequence_t *ptr;
473 keymap_entry_t tmp;
474
475 /*
476 * Validate the second keystroke.
477 */
478 if (second_entry >= ASCII_SET_SIZE)
479 return (B_FALSE);
480
481 if (lower->kbtrans_compose_map[second_entry] < 0)
482 return (B_FALSE);
483
484 /*
485 * Get them in code order, rather than press order.
486 */
487 if (first_entry > second_entry) {
488 tmp = first_entry;
489 first_entry = second_entry;
490 second_entry = tmp;
491 }
492
493 ptr = lower->kbtrans_compose_table +
494 lower->kbtrans_compose_map[first_entry];
495
496 while (ptr->first == first_entry) {
497 if (ptr->second == second_entry) {
498 *result_ptr = ptr->utf8;
499
500 return (B_TRUE);
501 }
502 ptr++;
503 }
504 return (B_FALSE);
505 }
506
507
508 /*
509 * kbtrans_find_entry:
510 * This routine finds the entry corresponding to the current shift
511 * state and keycode.
512 */
513 keymap_entry_t *
kbtrans_find_entry(struct kbtrans_lower * lower,uint_t mask,kbtrans_key_t key_station)514 kbtrans_find_entry(struct kbtrans_lower *lower, uint_t mask,
515 kbtrans_key_t key_station)
516 {
517 register struct keyboard *kp;
518 keymap_entry_t *km;
519 struct exception_map *ex;
520
521 kp = lower->kbtrans_keyboard;
522
523 if (kp == NULL)
524 return (NULL);
525
526 if (key_station < 0 || key_station >= kp->k_keymap_size)
527 return (NULL);
528
529 ex = kp->k_except;
530 if (ex != NULL) {
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);
535 }
536 }
537
538 if (mask & UPMASK)
539 km = kp->k_up;
540 else if (mask & NUMLOCKMASK)
541 km = kp->k_numlock;
542 else if (mask & CTRLMASK)
543 km = kp->k_control;
544 else if (mask & ALTGRAPHMASK)
545 km = kp->k_altgraph;
546 else if (mask & SHIFTMASK)
547 km = kp->k_shifted;
548 else if (mask & CAPSMASK)
549 km = kp->k_caps;
550 else km = kp->k_normal;
551
552 return (&km[key_station]);
553 }
554
555 #ifdef DEBUG
556 /*ARGSUSED*/
557 void
kbtrans_dprintf(void * un,const char * fmt,...)558 kbtrans_dprintf(void *un, const char *fmt, ...)
559 {
560 char buf[256];
561 va_list ap;
562
563 va_start(ap, fmt);
564 (void) vsprintf(buf, fmt, ap);
565 va_end(ap);
566
567 cmn_err(CE_CONT, "kbtrans: %s", buf);
568 }
569 #endif
570