xref: /illumos-gate/usr/src/uts/common/io/kbtrans/kbtrans.c (revision 598f4ceed9327d2d6c2325dd67cae3aa06f7fea6)
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
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
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
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 *
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
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