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 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * Generic keyboard support: translation
31 *
32 * This module is project private. Please see PSARC/1998/176 and
33 * PSARC/1998/026 for references to the kbtrans module.
34 *
35 * It is believed that it is safe to call these functions within debugger mode
36 * except kbtrans_dprintf. Debugger mode is a single threaded mode where most
37 * kernel services are not available, including memory allocation. Debugger
38 * mode is for kmdb and OBP debugging, where the debugger calls back into the
39 * kernel to obtain console input.
40 *
41 * Please be _very_ careful about what external functions you call.
42 */
43
44 #define KEYMAP_SIZE_VARIABLE
45
46 #include <sys/types.h>
47 #include <sys/cred.h>
48 #include <sys/ddi.h>
49 #include <sys/sunddi.h>
50 #include <sys/kmem.h>
51 #include <sys/kbd.h>
52 #include <sys/cmn_err.h>
53 #include <sys/modctl.h>
54 #include <sys/kbio.h>
55 #include <sys/vuid_event.h>
56 #include <sys/consdev.h>
57 #include <sys/kbtrans.h>
58 #include <sys/errno.h>
59 #include <sys/promif.h>
60 #include <sys/varargs.h>
61 #include "kbtrans_lower.h"
62
63 /*
64 * Internal Function Prototypes
65 */
66 static boolean_t kbtrans_do_compose(struct kbtrans_lower *, ushort_t,
67 ushort_t, ushort_t *);
68 static void kbtrans_translate(struct kbtrans_lower *,
69 struct keyboard_callback *, kbtrans_key_t,
70 enum keystate);
71 /*
72 * kbtrans_processkey:
73 *
74 * lower - state information used by the calling driver
75 * this parameter is passed back to the callback routines.
76 * key - scancode
77 * state - KEY_PRESSED / KEY_RELEASED
78 *
79 * This routine checks to see if there is a raw callback, and calls it
80 * if it exists. If there is no raw callback, the key is translated.
81 * The raw callback allows the driver that called the translation module
82 * to be passed untranslated scancodes.
83 */
84 void
kbtrans_processkey(struct kbtrans_lower * lower,struct keyboard_callback * cb,kbtrans_key_t key,enum keystate state)85 kbtrans_processkey(struct kbtrans_lower *lower,
86 struct keyboard_callback *cb,
87 kbtrans_key_t key,
88 enum keystate state)
89 {
90 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (lower, "kbtrans_processkey: "
91 "newstate=%d key=%d", state, key));
92
93 /*
94 * If there is a raw routine, then call it and return.
95 */
96 if (cb->kc_keypressed_raw != NULL) {
97
98 if (state == KEY_PRESSED) {
99
100 cb->kc_keypressed_raw(lower->kbtrans_upper, key);
101 } else {
102
103 cb->kc_keyreleased_raw(lower->kbtrans_upper, key);
104 }
105
106 return;
107 }
108
109 /*
110 * translate the scancode into a key.
111 */
112 kbtrans_translate(lower, cb, key, state);
113 }
114
115
116 /*
117 * kbtrans_translate:
118 *
119 * lower - state information used by the calling driver
120 * this parameter is passed back to the callback routines.
121 * key - scan code
122 * state - KEY_PRESSED / KEY_RELEASED
123 *
124 * Called to process key events if we are in TR_ASCII or TR_EVENT
125 * (sunview) mode. This routine will call the appropriate translation_callback
126 * for the character when it is done translating it.
127 */
128 static void
kbtrans_translate(struct kbtrans_lower * lower,struct keyboard_callback * cb,kbtrans_key_t key,enum keystate newstate)129 kbtrans_translate(struct kbtrans_lower *lower,
130 struct keyboard_callback *cb,
131 kbtrans_key_t key,
132 enum keystate newstate)
133 {
134 unsigned shiftmask;
135 register ushort_t entry;
136 register ushort_t entrytype;
137 ushort_t result_iso;
138 unsigned short *ke;
139 int i;
140 boolean_t good_compose;
141
142 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (lower, "KEY TRANSLATE "
143 "newstate=0x%x key=0x%x\n", newstate, key));
144
145 if (lower->kbtrans_keyboard == NULL) {
146 /*
147 * Nobody has told us about this keyboard yet.
148 */
149 return;
150 }
151
152 /*
153 * Get the current state of the shiftmask
154 */
155 shiftmask = lower->kbtrans_shiftmask;
156
157 /*
158 * If the key has been released, then or in the UPMASK flag.
159 */
160 if (newstate == KEY_RELEASED)
161 shiftmask |= UPMASK;
162
163 /*
164 * Based on the shiftmask, lookup the keymap entry that we should
165 * be using for this scancode.
166 */
167 ke = kbtrans_find_entry(lower, shiftmask, key);
168
169 if (ke == NULL) {
170 /*
171 * This is a gross error. Cancel the repeat key and exit,
172 * we can not translate this scancode.
173 */
174 cb->kc_cancel_repeat(lower->kbtrans_upper);
175
176 return;
177 }
178
179 /*
180 * Get the key for this scancode.
181 */
182 entry = *ke;
183
184 if (entry == NONL) {
185 /*
186 * NONL appears only in the Num Lock table, and indicates that
187 * this key is not affected by Num Lock. This means we should
188 * ask for the table we would have gotten had Num Lock not been
189 * down, and translate using that table.
190 */
191 ke = kbtrans_find_entry(lower, shiftmask & ~NUMLOCKMASK,
192 key);
193
194 if (ke == NULL) {
195 /*
196 * This is a gross error. Cancel the repeat key and
197 * exit, we can not translate this scancode.
198 */
199 cb->kc_cancel_repeat(lower->kbtrans_upper);
200
201 return;
202 }
203
204 /*
205 * Get the new key for this scancode.
206 */
207 entry = *ke;
208 }
209
210 /*
211 * The entrytype indicates what category of key we are processing.
212 * Categories include shift keys, function keys, and numeric keypad
213 * keys.
214 */
215 entrytype = (ushort_t)(entry & 0xFF00);
216
217 if (entrytype == SHIFTKEYS) {
218 /*
219 * Handle the state of toggle shifts specially.
220 * Ups should be ignored, and downs should be mapped to ups if
221 * that shift is currently on.
222 */
223 if ((1 << (entry & 0x0F)) &
224 lower->kbtrans_keyboard->k_toggleshifts) {
225 if ((1 << (entry & 0x0F)) &
226 lower->kbtrans_togglemask) {
227 newstate = KEY_RELEASED; /* toggling off */
228 } else {
229 newstate = KEY_PRESSED; /* toggling on */
230 }
231 }
232 } else {
233 /*
234 * Handle Compose and floating accent key sequences
235 */
236 switch (lower->kbtrans_state) {
237 case COMPOSE1:
238 if (newstate == KEY_RELEASED)
239
240 return;
241
242 if (entry < ASCII_SET_SIZE) {
243 if (lower->kbtrans_compose_map[entry] >= 0) {
244 lower->kbtrans_compose_key = entry;
245 lower->kbtrans_state = COMPOSE2;
246
247 return;
248 }
249 }
250 lower->kbtrans_state = NORMAL;
251 lower->kbtrans_led_state &= ~LED_COMPOSE;
252
253 cb->kc_setled(lower->kbtrans_upper);
254
255 return;
256
257 case COMPOSE2:
258 if (newstate == KEY_RELEASED)
259 return;
260
261 /* next state is "normal" */
262 lower->kbtrans_state = NORMAL;
263 lower->kbtrans_led_state &= ~LED_COMPOSE;
264
265 cb->kc_setled(lower->kbtrans_upper);
266
267 good_compose = kbtrans_do_compose(lower,
268 lower->kbtrans_compose_key, entry,
269 &result_iso);
270 if (good_compose) {
271 if (lower->kbtrans_compat)
272 result_iso += ISO_FIRST;
273 else
274 result_iso += EUC_FIRST;
275 cb->kc_keypressed(lower->kbtrans_upper,
276 entrytype, key, result_iso);
277 }
278 return;
279
280 case FLTACCENT:
281 if (newstate == KEY_RELEASED)
282
283 return;
284
285 /* next state is "normal" */
286 lower->kbtrans_state = NORMAL;
287 for (i = 0;
288 (lower->kbtrans_fltaccent_table[i].fa_entry
289 != lower->kbtrans_fltaccent_entry) ||
290 (lower->kbtrans_fltaccent_table[i].ascii != entry);
291 i++) {
292 if (lower->kbtrans_fltaccent_table[i].fa_entry
293 == 0) {
294 /* Invalid second key: ignore key */
295
296 return;
297 }
298 }
299
300 cb->kc_keypressed(lower->kbtrans_upper, entrytype,
301 key, (lower->kbtrans_compat ?
302 ISO_FIRST : EUC_FIRST) +
303 lower->kbtrans_fltaccent_table[i].iso);
304
305 return;
306 }
307 }
308
309 /*
310 * If the key is going down, and it's not one of the keys that doesn't
311 * auto-repeat, set up the auto-repeat timeout.
312 *
313 * The keys that don't auto-repeat are the Compose key,
314 * the shift keys, the "bucky bit" keys, the "floating accent" keys,
315 * and the function keys when in TR_EVENT mode.
316 */
317 if (newstate == KEY_PRESSED && entrytype != SHIFTKEYS &&
318 entrytype != BUCKYBITS && entrytype != FUNNY &&
319 entrytype != FA_CLASS) {
320
321 if (lower->kbtrans_repeatkey != key) {
322 cb->kc_cancel_repeat(lower->kbtrans_upper);
323 cb->kc_setup_repeat(lower->kbtrans_upper, entrytype,
324 key);
325 }
326 /* key going up */
327 } else if (key == lower->kbtrans_repeatkey) {
328
329 cb->kc_cancel_repeat(lower->kbtrans_upper);
330 }
331
332 if (newstate == KEY_RELEASED) {
333 cb->kc_keyreleased(lower->kbtrans_upper, key);
334 }
335
336 /*
337 * We assume here that keys other than shift keys and bucky keys have
338 * entries in the "up" table that cause nothing to be done, and thus we
339 * don't have to check for newstate == KEY_RELEASED.
340 */
341 switch (entrytype) {
342
343 case 0x0: /* regular key */
344 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
345 entry | lower->kbtrans_buckybits);
346 break;
347
348 case SHIFTKEYS: {
349 uint_t shiftbit = 1 << (entry & 0x0F);
350
351 /* Modify toggle state (see toggle processing above) */
352 if (shiftbit & lower->kbtrans_keyboard->k_toggleshifts) {
353 if (newstate == KEY_RELEASED) {
354 if (shiftbit == CAPSMASK) {
355 lower->kbtrans_led_state &=
356 ~LED_CAPS_LOCK;
357
358 cb->kc_setled(lower->kbtrans_upper);
359
360 } else if (shiftbit == NUMLOCKMASK) {
361 lower->kbtrans_led_state &=
362 ~LED_NUM_LOCK;
363
364 cb->kc_setled(lower->kbtrans_upper);
365 }
366 lower->kbtrans_togglemask &= ~shiftbit;
367 } else {
368 if (shiftbit == CAPSMASK) {
369 lower->kbtrans_led_state |=
370 LED_CAPS_LOCK;
371
372 cb->kc_setled(lower->kbtrans_upper);
373 } else if (shiftbit == NUMLOCKMASK) {
374 lower->kbtrans_led_state |=
375 LED_NUM_LOCK;
376
377 cb->kc_setled(lower->kbtrans_upper);
378 }
379 lower->kbtrans_togglemask |= shiftbit;
380 }
381 }
382
383 if (newstate == KEY_RELEASED)
384 lower->kbtrans_shiftmask &= ~shiftbit;
385 else
386 lower->kbtrans_shiftmask |= shiftbit;
387
388 if (newstate == KEY_PRESSED) {
389 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
390 entry);
391 }
392
393 break;
394 }
395
396 case BUCKYBITS:
397 lower->kbtrans_buckybits ^= 1 << (7 + (entry & 0x0F));
398
399 if (newstate == KEY_PRESSED) {
400 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
401 entry);
402 }
403
404 break;
405
406 case FUNNY:
407 switch (entry) {
408 case NOP:
409 break;
410
411 case IDLE:
412 /* Fall thru into RESET code */
413 /* FALLTHRU */
414 case RESET:
415 case ERROR:
416 lower->kbtrans_shiftmask &=
417 lower->kbtrans_keyboard->k_idleshifts;
418
419 lower->kbtrans_shiftmask |=
420 lower->kbtrans_togglemask;
421
422 lower->kbtrans_buckybits &=
423 lower->kbtrans_keyboard->k_idlebuckys;
424
425 cb->kc_cancel_repeat(lower->kbtrans_upper);
426
427 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
428 entry);
429
430 break;
431
432
433 case COMPOSE:
434 lower->kbtrans_state = COMPOSE1;
435 lower->kbtrans_led_state |= LED_COMPOSE;
436 cb->kc_setled(lower->kbtrans_upper);
437 break;
438 /*
439 * Remember when adding new entries that,
440 * if they should NOT auto-repeat,
441 * they should be put into the IF statement
442 * just above this switch block.
443 */
444 default:
445 /* Ignore it */
446 break;
447 }
448 break;
449
450 case FA_CLASS:
451 if (lower->kbtrans_state == NORMAL) {
452 lower->kbtrans_fltaccent_entry = entry;
453 lower->kbtrans_state = FLTACCENT;
454 }
455 break;
456
457 case STRING:
458 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry);
459
460 break;
461
462 case FUNCKEYS:
463 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry);
464
465 break;
466
467 /*
468 * Remember when adding new entries that,
469 * if they should NOT auto-repeat,
470 * they should be put into the IF statement
471 * just above this switch block.
472 */
473 case PADKEYS:
474 cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry);
475
476 break;
477 }
478 }
479
480 /*
481 * kbtrans_do_compose:
482 * Given a two key compose sequence, lookup the iso equivalent and put
483 * the result in the result_iso_ptr.
484 */
485 static boolean_t
kbtrans_do_compose(struct kbtrans_lower * lower,ushort_t first_entry,ushort_t second_entry,ushort_t * result_iso_ptr)486 kbtrans_do_compose(struct kbtrans_lower *lower,
487 ushort_t first_entry,
488 ushort_t second_entry,
489 ushort_t *result_iso_ptr)
490 {
491 struct compose_sequence_t *ptr;
492 ushort_t tmp;
493
494 /*
495 * Validate the second keystroke.
496 */
497 if (second_entry >= ASCII_SET_SIZE)
498 return (B_FALSE);
499
500 if (lower->kbtrans_compose_map[second_entry] < 0)
501 return (B_FALSE);
502
503 /*
504 * Get them in code order, rather than press order.
505 */
506 if (first_entry > second_entry) {
507 tmp = first_entry;
508 first_entry = second_entry;
509 second_entry = tmp;
510 }
511
512 ptr = lower->kbtrans_compose_table +
513 lower->kbtrans_compose_map[first_entry];
514
515 while (ptr->first == first_entry) {
516 if (ptr->second == second_entry) {
517 *result_iso_ptr = ptr->iso;
518
519 return (B_TRUE);
520 }
521 ptr++;
522 }
523 return (B_FALSE);
524 }
525
526
527 /*
528 * kbtrans_find_entry:
529 * This routine finds the entry corresponding to the current shift
530 * state and keycode.
531 */
532 unsigned short *
kbtrans_find_entry(struct kbtrans_lower * lower,register uint_t mask,kbtrans_key_t key_station)533 kbtrans_find_entry(struct kbtrans_lower *lower,
534 register uint_t mask,
535 kbtrans_key_t key_station)
536 {
537 register struct keyboard *kp;
538 keymap_entry_t *km;
539 struct exception_map *ex;
540
541 kp = lower->kbtrans_keyboard;
542
543 if (kp == NULL)
544 return (NULL);
545
546 if (key_station < 0 || key_station >= kp->k_keymap_size)
547 return (NULL);
548
549 ex = kp->k_except;
550 if (ex != NULL) {
551 for (; ex->exc_care != 0; ex++) {
552 if ((mask & ex->exc_care) == ex->exc_mask &&
553 key_station == ex->exc_key)
554 return (&ex->exc_entry);
555 }
556 }
557
558 if (mask & UPMASK)
559 km = kp->k_up;
560 else if (mask & NUMLOCKMASK)
561 km = kp->k_numlock;
562 else if (mask & CTRLMASK)
563 km = kp->k_control;
564 else if (mask & ALTGRAPHMASK)
565 km = kp->k_altgraph;
566 else if (mask & SHIFTMASK)
567 km = kp->k_shifted;
568 else if (mask & CAPSMASK)
569 km = kp->k_caps;
570 else km = kp->k_normal;
571
572 return (&km[key_station]);
573 }
574
575 #ifdef DEBUG
576 /*ARGSUSED*/
577 void
kbtrans_dprintf(void * un,const char * fmt,...)578 kbtrans_dprintf(void *un, const char *fmt, ...)
579 {
580 char buf[256];
581 va_list ap;
582
583 va_start(ap, fmt);
584 (void) vsprintf(buf, fmt, ap);
585 va_end(ap);
586
587 cmn_err(CE_CONT, "kbtrans: %s", buf);
588 }
589 #endif
590