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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2019 Joyent, Inc.
26 */
27
28 /*
29 * Generic keyboard support: STREAMS and administration.
30 */
31
32 #define KEYMAP_SIZE_VARIABLE
33
34 #include <sys/types.h>
35 #include <sys/cred.h>
36 #include <sys/stream.h>
37 #include <sys/stropts.h>
38 #include <sys/strsun.h>
39 #include <sys/ddi.h>
40 #include <sys/vuid_event.h>
41 #include <sys/modctl.h>
42 #include <sys/errno.h>
43 #include <sys/kmem.h>
44 #include <sys/cmn_err.h>
45 #include <sys/kbd.h>
46 #include <sys/kbio.h>
47 #include <sys/consdev.h>
48 #include <sys/kbtrans.h>
49 #include <sys/policy.h>
50 #include <sys/sunldi.h>
51 #include <sys/class.h>
52 #include <sys/spl.h>
53 #include "kbtrans_lower.h"
54 #include "kbtrans_streams.h"
55
56 #ifdef DEBUG
57 int kbtrans_errmask;
58 int kbtrans_errlevel;
59 #endif
60
61 #define KB_NR_FUNCKEYS 12
62
63 /*
64 * Overrides for tuning keyboard autorepeat behaviour:
65 */
66 int kbtrans_repeat_count = -1;
67 int kbtrans_repeat_rate;
68 int kbtrans_repeat_delay;
69
70 /*
71 * Override whether to print a message when the keyboard event queue overflows:
72 */
73 int kbtrans_overflow_msg = 1;
74
75 /*
76 * Override whether to drop "Scroll Lock" key presses in TR_ASCII mode:
77 */
78 int kbtrans_ignore_scroll_lock = 1;
79
80 /*
81 * Override for the number of key stations we will track in the down state at
82 * one time. By default we assume most keyboards will be operated by people
83 * with up to ten fingers, plus some safety margin. This size is only read
84 * once at attach time.
85 */
86 int kbtrans_downs_size = 15;
87
88 /*
89 * modload support
90 */
91 extern struct mod_ops mod_miscops;
92
93 static struct modlmisc modlmisc = {
94 &mod_miscops, /* Type of module */
95 "kbtrans (key translation)"
96 };
97
98 static struct modlinkage modlinkage = {
99 MODREV_1, (void *)&modlmisc, NULL
100 };
101
102 int
_init(void)103 _init(void)
104 {
105 return (mod_install(&modlinkage));
106 }
107
108 int
_fini(void)109 _fini(void)
110 {
111 return (mod_remove(&modlinkage));
112 }
113
114 int
_info(struct modinfo * modinfop)115 _info(struct modinfo *modinfop)
116 {
117 return (mod_info(&modlinkage, modinfop));
118 }
119
120 /*
121 * Internal Function Prototypes
122 */
123 static char *kbtrans_strsetwithdecimal(char *, uint_t, uint_t);
124 static void kbtrans_set_translation_callback(struct kbtrans *);
125 static void kbtrans_reioctl(void *);
126 static void kbtrans_send_esc_event(char, struct kbtrans *);
127 static void kbtrans_keypressed(struct kbtrans *, uchar_t, Firm_event *,
128 ushort_t);
129 static void kbtrans_putbuf(char *, queue_t *);
130 static void kbtrans_cancelrpt(struct kbtrans *);
131 static void kbtrans_queuepress(struct kbtrans *, uchar_t, Firm_event *);
132 static void kbtrans_putcode(register struct kbtrans *, uint_t);
133 static void kbtrans_keyreleased(struct kbtrans *, uchar_t);
134 static void kbtrans_queueevent(struct kbtrans *, Firm_event *);
135 static void kbtrans_untrans_keypressed_raw(struct kbtrans *, kbtrans_key_t);
136 static void kbtrans_untrans_keyreleased_raw(struct kbtrans *, kbtrans_key_t);
137 static void kbtrans_ascii_keypressed(struct kbtrans *, uint_t,
138 kbtrans_key_t, uint_t);
139 static void kbtrans_ascii_keyreleased(struct kbtrans *, kbtrans_key_t);
140 static void kbtrans_ascii_setup_repeat(struct kbtrans *, uint_t, kbtrans_key_t);
141 static void kbtrans_trans_event_keypressed(struct kbtrans *, uint_t,
142 kbtrans_key_t, uint_t);
143 static void kbtrans_trans_event_keyreleased(struct kbtrans *, kbtrans_key_t);
144 static void kbtrans_trans_event_setup_repeat(struct kbtrans *, uint_t,
145 kbtrans_key_t);
146 static void kbtrans_rpt(void *);
147 static void kbtrans_setled(struct kbtrans *);
148 static void kbtrans_flush(struct kbtrans *);
149 static enum kbtrans_message_response kbtrans_ioctl(struct kbtrans *, mblk_t *);
150 static int kbtrans_setkey(struct kbtrans_lower *, struct kiockey *, cred_t *);
151 static int kbtrans_getkey(struct kbtrans_lower *, struct kiockey *);
152 static int kbtrans_skey(struct kbtrans_lower *, struct kiockeymap *, cred_t *);
153 static int kbtrans_gkey(struct kbtrans_lower *, struct kiockeymap *);
154
155 /*
156 * Keyboard Translation Mode (TR_NONE)
157 *
158 * Functions to be called when keyboard translation is turned off
159 * and up/down key codes are reported.
160 */
161 struct keyboard_callback untrans_event_callback = {
162 kbtrans_untrans_keypressed_raw,
163 kbtrans_untrans_keyreleased_raw,
164 NULL,
165 NULL,
166 NULL,
167 NULL,
168 NULL,
169 };
170
171 /*
172 * Keyboard Translation Mode (TR_ASCII)
173 *
174 * Functions to be called when ISO 8859/1 codes are reported
175 */
176 struct keyboard_callback ascii_callback = {
177 NULL,
178 NULL,
179 kbtrans_ascii_keypressed,
180 kbtrans_ascii_keyreleased,
181 kbtrans_ascii_setup_repeat,
182 kbtrans_cancelrpt,
183 kbtrans_setled,
184 };
185
186 /*
187 * Keyboard Translation Mode (TR_EVENT)
188 *
189 * Functions to be called when firm_events are reported.
190 */
191 struct keyboard_callback trans_event_callback = {
192 NULL,
193 NULL,
194 kbtrans_trans_event_keypressed,
195 kbtrans_trans_event_keyreleased,
196 kbtrans_trans_event_setup_repeat,
197 kbtrans_cancelrpt,
198 kbtrans_setled,
199 };
200
201 static void
progressbar_key_abort_thread(struct kbtrans * upper)202 progressbar_key_abort_thread(struct kbtrans *upper)
203 {
204 ldi_ident_t li;
205 extern void progressbar_key_abort(ldi_ident_t);
206
207 if (ldi_ident_from_stream(upper->kbtrans_streams_readq, &li) != 0) {
208 cmn_err(CE_NOTE, "!ldi_ident_from_stream failed");
209 } else {
210 mutex_enter(&upper->progressbar_key_abort_lock);
211 while (upper->progressbar_key_abort_flag == 0)
212 cv_wait(&upper->progressbar_key_abort_cv,
213 &upper->progressbar_key_abort_lock);
214 if (upper->progressbar_key_abort_flag == 1) {
215 mutex_exit(&upper->progressbar_key_abort_lock);
216 progressbar_key_abort(li);
217 } else {
218 mutex_exit(&upper->progressbar_key_abort_lock);
219 }
220 ldi_ident_release(li);
221 }
222
223 thread_exit();
224 }
225
226 /*
227 * kbtrans_streams_init:
228 * Initialize the stream, keytables, callbacks, etc.
229 */
230 int
kbtrans_streams_init(queue_t * q,int sflag,struct kbtrans_hardware * hw,struct kbtrans_callbacks * hw_cb,struct kbtrans ** ret_kbd,int initial_leds,int initial_led_mask)231 kbtrans_streams_init(queue_t *q, int sflag, struct kbtrans_hardware *hw,
232 struct kbtrans_callbacks *hw_cb, struct kbtrans **ret_kbd,
233 int initial_leds, int initial_led_mask)
234 {
235 struct kbtrans *upper;
236 struct kbtrans_lower *lower;
237 kthread_t *tid;
238
239 /*
240 * Default to relatively generic tables.
241 */
242 extern signed char kb_compose_map[];
243 extern struct compose_sequence_t kb_compose_table[];
244 extern struct fltaccent_sequence_t kb_fltaccent_table[];
245 extern char keystringtab[][KTAB_STRLEN];
246 extern unsigned char kb_numlock_table[];
247
248 /* Set these up only once so that they could be changed from adb */
249 if (!kbtrans_repeat_rate) {
250 kbtrans_repeat_rate = (hz + 29) / 30;
251 kbtrans_repeat_delay = hz / 2;
252 }
253
254 switch (sflag) {
255
256 case MODOPEN:
257 break;
258
259 case CLONEOPEN:
260 DPRINTF(PRINT_L1, PRINT_MASK_OPEN, (NULL,
261 "kbtrans_streams_init: Clone open not supported"));
262
263 return (EINVAL);
264 }
265
266 /* allocate keyboard state structure */
267 upper = kmem_zalloc(sizeof (struct kbtrans), KM_SLEEP);
268
269 *ret_kbd = upper;
270
271 upper->kbtrans_polled_buf[0] = '\0';
272 upper->kbtrans_polled_pending_chars = upper->kbtrans_polled_buf;
273
274 upper->kbtrans_streams_hw = hw;
275 upper->kbtrans_streams_hw_callbacks = hw_cb;
276 upper->kbtrans_streams_readq = q;
277 upper->kbtrans_streams_iocpending = NULL;
278 upper->kbtrans_streams_translatable = TR_CAN;
279 upper->kbtrans_overflow_cnt = 0;
280 upper->kbtrans_streams_translate_mode = TR_ASCII;
281
282 /* Set the translation callback based on the translation type */
283 kbtrans_set_translation_callback(upper);
284
285 lower = &upper->kbtrans_lower;
286
287 /*
288 * Set defaults for relatively generic tables.
289 */
290 lower->kbtrans_compose_map = kb_compose_map;
291 lower->kbtrans_compose_table = kb_compose_table;
292 lower->kbtrans_fltaccent_table = kb_fltaccent_table;
293 lower->kbtrans_numlock_table = kb_numlock_table;
294 lower->kbtrans_keystringtab = keystringtab;
295
296 lower->kbtrans_upper = upper;
297 lower->kbtrans_compat = 1;
298
299 /*
300 * We have a generic default for the LED state, and let the
301 * hardware-specific driver supply overrides.
302 */
303 lower->kbtrans_led_state = 0;
304 lower->kbtrans_led_state &= ~initial_led_mask;
305 lower->kbtrans_led_state |= initial_leds;
306 lower->kbtrans_togglemask = 0;
307
308 if (lower->kbtrans_led_state & LED_CAPS_LOCK)
309 lower->kbtrans_togglemask |= CAPSMASK;
310 if (lower->kbtrans_led_state & LED_NUM_LOCK)
311 lower->kbtrans_togglemask |= NUMLOCKMASK;
312
313 #if defined(SCROLLMASK)
314 if (lower->kbtrans_led_state & LED_SCROLL_LOCK)
315 lower->kbtrans_togglemask |= SCROLLMASK;
316 #endif
317
318 lower->kbtrans_shiftmask = lower->kbtrans_togglemask;
319
320 upper->kbtrans_streams_vuid_addr.ascii = ASCII_FIRST;
321 upper->kbtrans_streams_vuid_addr.top = TOP_FIRST;
322 upper->kbtrans_streams_vuid_addr.vkey = VKEY_FIRST;
323
324 /* Allocate dynamic memory for downs table */
325 upper->kbtrans_streams_num_downs_entries = kbtrans_downs_size;
326 upper->kbtrans_streams_downs_bytes =
327 (uint32_t)(kbtrans_downs_size * sizeof (Key_event));
328 upper->kbtrans_streams_downs =
329 kmem_zalloc(upper->kbtrans_streams_downs_bytes, KM_SLEEP);
330 upper->kbtrans_streams_abortable = B_FALSE;
331
332 upper->kbtrans_streams_flags = KBTRANS_STREAMS_OPEN;
333
334 upper->progressbar_key_abort_flag = 0;
335 cv_init(&upper->progressbar_key_abort_cv, NULL, CV_DEFAULT, NULL);
336 /* this counts on no keyboards being above ipl 12 */
337 mutex_init(&upper->progressbar_key_abort_lock, NULL, MUTEX_SPIN,
338 (void *)ipltospl(12));
339 tid = thread_create(NULL, 0, progressbar_key_abort_thread, upper,
340 0, &p0, TS_RUN, minclsyspri);
341 upper->progressbar_key_abort_t_did = tid->t_did;
342
343 DPRINTF(PRINT_L1, PRINT_MASK_OPEN, (upper, "kbtrans_streams_init "
344 "exiting"));
345 return (0);
346 }
347
348
349 /*
350 * kbtrans_streams_fini:
351 * Free structures and uninitialize the stream
352 */
353 int
kbtrans_streams_fini(struct kbtrans * upper)354 kbtrans_streams_fini(struct kbtrans *upper)
355 {
356 /*
357 * Since we're about to destroy our private data, turn off
358 * our open flag first, so we don't accept any more input
359 * and try to use that data.
360 */
361 upper->kbtrans_streams_flags = 0;
362
363 /* clear all timeouts */
364 if (upper->kbtrans_streams_bufcallid) {
365 qunbufcall(upper->kbtrans_streams_readq,
366 upper->kbtrans_streams_bufcallid);
367 }
368 if (upper->kbtrans_streams_rptid) {
369 (void) quntimeout(upper->kbtrans_streams_readq,
370 upper->kbtrans_streams_rptid);
371 }
372 kmem_free(upper->kbtrans_streams_downs,
373 upper->kbtrans_streams_downs_bytes);
374
375 mutex_enter(&upper->progressbar_key_abort_lock);
376 if (upper->progressbar_key_abort_flag == 0) {
377 upper->progressbar_key_abort_flag = 2;
378 cv_signal(&upper->progressbar_key_abort_cv);
379 mutex_exit(&upper->progressbar_key_abort_lock);
380 thread_join(upper->progressbar_key_abort_t_did);
381 } else {
382 mutex_exit(&upper->progressbar_key_abort_lock);
383 }
384 cv_destroy(&upper->progressbar_key_abort_cv);
385 mutex_destroy(&upper->progressbar_key_abort_lock);
386
387 kmem_free(upper, sizeof (struct kbtrans));
388
389 DPRINTF(PRINT_L1, PRINT_MASK_CLOSE, (upper, "kbtrans_streams_fini "
390 "exiting"));
391 return (0);
392 }
393
394 /*
395 * kbtrans_streams_releaseall :
396 * This function releases all the held keys.
397 */
398 void
kbtrans_streams_releaseall(struct kbtrans * upper)399 kbtrans_streams_releaseall(struct kbtrans *upper)
400 {
401 register struct key_event *ke;
402 register int i;
403
404 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL, "USBKBM RELEASE ALL\n"));
405
406 /* Scan table of down key stations */
407 for (i = 0, ke = upper->kbtrans_streams_downs;
408 i < upper->kbtrans_streams_num_downs_entries; i++, ke++) {
409
410 /* Key station not zero */
411 if (ke->key_station) {
412
413 kbtrans_keyreleased(upper, ke->key_station);
414 /* kbtrans_keyreleased resets downs entry */
415 }
416 }
417 }
418
419 /*
420 * kbtrans_streams_message:
421 * keyboard module output queue put procedure: handles M_IOCTL
422 * messages.
423 *
424 * Return KBTRANS_MESSAGE_HANDLED if the message was handled by
425 * kbtrans and KBTRANS_MESSAGE_NOT_HANDLED otherwise. If
426 * KBTRANS_MESSAGE_HANDLED is returned, no further action is required.
427 * If KBTRANS_MESSAGE_NOT_HANDLED is returned, the hardware module
428 * is responsible for any action.
429 */
430 enum kbtrans_message_response
kbtrans_streams_message(struct kbtrans * upper,register mblk_t * mp)431 kbtrans_streams_message(struct kbtrans *upper, register mblk_t *mp)
432 {
433 queue_t *q = upper->kbtrans_streams_readq;
434 enum kbtrans_message_response ret;
435
436 DPRINTF(PRINT_L1, PRINT_MASK_ALL, (upper,
437 "kbtrans_streams_message entering"));
438 /*
439 * Process M_FLUSH, and some M_IOCTL, messages here; pass
440 * everything else down.
441 */
442 switch (mp->b_datap->db_type) {
443
444 case M_IOCTL:
445 ret = kbtrans_ioctl(upper, mp);
446 break;
447
448 case M_FLUSH:
449 if (*mp->b_rptr & FLUSHW)
450 flushq(q, FLUSHDATA);
451 if (*mp->b_rptr & FLUSHR)
452 flushq(RD(q), FLUSHDATA);
453 /*
454 * White lie: we say we didn't handle the message,
455 * so that it gets handled by our client.
456 */
457 ret = KBTRANS_MESSAGE_NOT_HANDLED;
458 break;
459
460 default:
461 ret = KBTRANS_MESSAGE_NOT_HANDLED;
462 break;
463
464 }
465 DPRINTF(PRINT_L1, PRINT_MASK_ALL, (upper,
466 "kbtrans_streams_message exiting\n"));
467
468 return (ret);
469 }
470
471 /*
472 * kbtrans_streams_key:
473 * When a key is pressed or released, the hardware module should
474 * call kbtrans, passing the key number and its new
475 * state. kbtrans is responsible for autorepeat handling;
476 * the hardware module should report only actual press/release
477 * events, suppressing any hardware-generated autorepeat.
478 */
479 void
kbtrans_streams_key(struct kbtrans * upper,kbtrans_key_t key,enum keystate state)480 kbtrans_streams_key(struct kbtrans *upper, kbtrans_key_t key,
481 enum keystate state)
482 {
483 struct kbtrans_lower *lower;
484 struct keyboard *kp;
485
486 lower = &upper->kbtrans_lower;
487 kp = lower->kbtrans_keyboard;
488
489 /* trigger switch back to text mode */
490 mutex_enter(&upper->progressbar_key_abort_lock);
491 if (upper->progressbar_key_abort_flag == 0) {
492 upper->progressbar_key_abort_flag = 1;
493 cv_signal(&upper->progressbar_key_abort_cv);
494 }
495 mutex_exit(&upper->progressbar_key_abort_lock);
496
497 if (upper->kbtrans_streams_abortable) {
498 switch (upper->kbtrans_streams_abort_state) {
499 case ABORT_NORMAL:
500 if (state != KEY_PRESSED)
501 break;
502
503 if (key == (kbtrans_key_t)kp->k_abort1 ||
504 key == (kbtrans_key_t)kp->k_abort1a) {
505 upper->kbtrans_streams_abort_state =
506 ABORT_ABORT1_RECEIVED;
507 upper->kbtrans_streams_abort1_key = key;
508 return;
509 }
510 /* Shift key needs to be sent to upper immediately */
511 if (key == (kbtrans_key_t)kp->k_newabort1 ||
512 key == (kbtrans_key_t)kp->k_newabort1a) {
513 upper->kbtrans_streams_abort_state =
514 NEW_ABORT_ABORT1_RECEIVED;
515 upper->kbtrans_streams_new_abort1_key = key;
516 }
517 break;
518 case ABORT_ABORT1_RECEIVED:
519 upper->kbtrans_streams_abort_state = ABORT_NORMAL;
520 if (state == KEY_PRESSED &&
521 key == (kbtrans_key_t)kp->k_abort2) {
522 abort_sequence_enter((char *)NULL);
523 return;
524 } else {
525 kbtrans_processkey(lower,
526 upper->kbtrans_streams_callback,
527 upper->kbtrans_streams_abort1_key,
528 KEY_PRESSED);
529 }
530 break;
531 case NEW_ABORT_ABORT1_RECEIVED:
532 upper->kbtrans_streams_abort_state = ABORT_NORMAL;
533 if (state == KEY_PRESSED &&
534 key == (kbtrans_key_t)kp->k_newabort2) {
535 abort_sequence_enter((char *)NULL);
536 kbtrans_processkey(lower,
537 upper->kbtrans_streams_callback,
538 upper->kbtrans_streams_new_abort1_key,
539 KEY_RELEASED);
540 return;
541 }
542 }
543 }
544
545 kbtrans_processkey(lower, upper->kbtrans_streams_callback, key, state);
546 }
547
548 /*
549 * kbtrans_streams_set_keyboard:
550 * At any time after calling kbtrans_streams_init, the hardware
551 * module should make this call to report the id of the keyboard
552 * attached. id is the keyboard type, typically KB_SUN4,
553 * KB_PC, or KB_USB.
554 */
555 void
kbtrans_streams_set_keyboard(struct kbtrans * upper,int id,struct keyboard * k)556 kbtrans_streams_set_keyboard(struct kbtrans *upper, int id, struct keyboard *k)
557 {
558 upper->kbtrans_lower.kbtrans_keyboard = k;
559 upper->kbtrans_streams_id = id;
560 }
561
562 /*
563 * kbtrans_streams_has_reset:
564 * At any time between kbtrans_streams_init and kbtrans_streams_fini,
565 * the hardware module can call this routine to report that the
566 * keyboard has been reset, e.g. by being unplugged and reattached.
567 */
568 /*ARGSUSED*/
569 void
kbtrans_streams_has_reset(struct kbtrans * upper)570 kbtrans_streams_has_reset(struct kbtrans *upper)
571 {
572 /*
573 * If this routine is implemented it should probably (a)
574 * simulate releases of all pressed keys and (b) call
575 * the hardware module to set the LEDs.
576 */
577 }
578
579 /*
580 * kbtrans_streams_enable:
581 * This is the routine that is called back when the the stream is ready
582 * to take messages.
583 */
584 void
kbtrans_streams_enable(struct kbtrans * upper)585 kbtrans_streams_enable(struct kbtrans *upper)
586 {
587 /* Set the LED's */
588 kbtrans_setled(upper);
589 }
590
591 /*
592 * kbtrans_streams_setled():
593 * This is the routine that is called to only update the led state
594 * in kbtrans.
595 */
596 void
kbtrans_streams_setled(struct kbtrans * upper,int led_state)597 kbtrans_streams_setled(struct kbtrans *upper, int led_state)
598 {
599 struct kbtrans_lower *lower;
600
601 lower = &upper->kbtrans_lower;
602 lower->kbtrans_led_state = (uchar_t)led_state;
603
604 if (lower->kbtrans_led_state & LED_CAPS_LOCK)
605 lower->kbtrans_togglemask |= CAPSMASK;
606 if (lower->kbtrans_led_state & LED_NUM_LOCK)
607 lower->kbtrans_togglemask |= NUMLOCKMASK;
608
609 #if defined(SCROLLMASK)
610 if (lower->kbtrans_led_state & LED_SCROLL_LOCK)
611 lower->kbtrans_togglemask |= SCROLLMASK;
612 #endif
613
614 lower->kbtrans_shiftmask = lower->kbtrans_togglemask;
615
616 }
617
618 /*
619 * kbtrans_streams_set_queue:
620 * Set the overlying queue, to support multiplexors.
621 */
622 void
kbtrans_streams_set_queue(struct kbtrans * upper,queue_t * q)623 kbtrans_streams_set_queue(struct kbtrans *upper, queue_t *q)
624 {
625
626 upper->kbtrans_streams_readq = q;
627 }
628
629 /*
630 * kbtrans_streams_get_queue:
631 * Return the overlying queue.
632 */
633 queue_t *
kbtrans_streams_get_queue(struct kbtrans * upper)634 kbtrans_streams_get_queue(struct kbtrans *upper)
635 {
636 return (upper->kbtrans_streams_readq);
637 }
638
639 /*
640 * kbtrans_streams_untimeout
641 * Cancell all timeout
642 */
643 void
kbtrans_streams_untimeout(struct kbtrans * upper)644 kbtrans_streams_untimeout(struct kbtrans *upper)
645 {
646 /* clear all timeouts */
647 if (upper->kbtrans_streams_bufcallid) {
648 qunbufcall(upper->kbtrans_streams_readq,
649 upper->kbtrans_streams_bufcallid);
650 upper->kbtrans_streams_bufcallid = 0;
651 }
652 if (upper->kbtrans_streams_rptid) {
653 (void) quntimeout(upper->kbtrans_streams_readq,
654 upper->kbtrans_streams_rptid);
655 upper->kbtrans_streams_rptid = 0;
656 }
657 }
658
659 /*
660 * kbtrans_reioctl:
661 * This function is set up as call-back function should an ioctl fail
662 * to allocate required resources.
663 */
664 static void
kbtrans_reioctl(void * arg)665 kbtrans_reioctl(void *arg)
666 {
667 struct kbtrans *upper = (struct kbtrans *)arg;
668 mblk_t *mp;
669
670 upper->kbtrans_streams_bufcallid = 0;
671
672 if ((mp = upper->kbtrans_streams_iocpending) != NULL) {
673 /* not pending any more */
674 upper->kbtrans_streams_iocpending = NULL;
675 (void) kbtrans_ioctl(upper, mp);
676 }
677 }
678
679 /*
680 * kbtrans_ioctl:
681 * process ioctls we recognize and own. Otherwise, pass it down.
682 */
683 static enum kbtrans_message_response
kbtrans_ioctl(struct kbtrans * upper,register mblk_t * mp)684 kbtrans_ioctl(struct kbtrans *upper, register mblk_t *mp)
685 {
686 register struct iocblk *iocp;
687 register short new_translate;
688 register Vuid_addr_probe *addr_probe;
689 register short *addr_ptr;
690 size_t ioctlrespsize;
691 int err = 0;
692 struct kbtrans_lower *lower;
693 mblk_t *datap;
694 int translate;
695
696 static int kiocgetkey, kiocsetkey;
697
698 lower = &upper->kbtrans_lower;
699
700 iocp = (struct iocblk *)mp->b_rptr;
701
702 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper,
703 "kbtrans_ioctl: ioc_cmd 0x%x - ", iocp->ioc_cmd));
704 switch (iocp->ioc_cmd) {
705
706 case VUIDSFORMAT:
707 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDSFORMAT\n"));
708
709 err = miocpullup(mp, sizeof (int));
710 if (err != 0)
711 break;
712 new_translate = (*(int *)mp->b_cont->b_rptr == VUID_NATIVE) ?
713 TR_ASCII : TR_EVENT;
714
715 if (new_translate == upper->kbtrans_streams_translate_mode)
716 break;
717 upper->kbtrans_streams_translate_mode = new_translate;
718
719 kbtrans_set_translation_callback(upper);
720
721 kbtrans_flush(upper);
722 break;
723
724 case KIOCTRANS:
725 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCTRANS\n"));
726 err = miocpullup(mp, sizeof (int));
727 if (err != 0)
728 break;
729 new_translate = *(int *)mp->b_cont->b_rptr;
730 if (new_translate == upper->kbtrans_streams_translate_mode)
731 break;
732 upper->kbtrans_streams_translate_mode = new_translate;
733 kbtrans_set_translation_callback(upper);
734
735 kbtrans_flush(upper);
736 break;
737
738 case KIOCSLED:
739 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSLED\n"));
740
741 err = miocpullup(mp, sizeof (uchar_t));
742 if (err != 0)
743 break;
744 lower->kbtrans_led_state = *(uchar_t *)mp->b_cont->b_rptr;
745
746 kbtrans_setled(upper);
747 break;
748
749 case KIOCGLED:
750 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGLED\n"));
751 if ((datap = allocb(sizeof (uchar_t), BPRI_HI)) == NULL) {
752 ioctlrespsize = sizeof (int);
753 goto allocfailure;
754 }
755
756 *(uchar_t *)datap->b_wptr = lower->kbtrans_led_state;
757 datap->b_wptr += sizeof (uchar_t);
758 if (mp->b_cont)
759 freemsg(mp->b_cont);
760 mp->b_cont = datap;
761 iocp->ioc_count = sizeof (uchar_t);
762 break;
763
764 case VUIDGFORMAT:
765 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDGFORMAT\n"));
766 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
767 ioctlrespsize = sizeof (int);
768 goto allocfailure;
769 }
770 *(int *)datap->b_wptr =
771 (upper->kbtrans_streams_translate_mode == TR_EVENT ||
772 upper->kbtrans_streams_translate_mode == TR_UNTRANS_EVENT) ?
773 VUID_FIRM_EVENT: VUID_NATIVE;
774 datap->b_wptr += sizeof (int);
775 if (mp->b_cont) /* free msg to prevent memory leak */
776 freemsg(mp->b_cont);
777 mp->b_cont = datap;
778 iocp->ioc_count = sizeof (int);
779 break;
780
781 case KIOCGTRANS:
782 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGTRANS\n"));
783 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
784 ioctlrespsize = sizeof (int);
785 goto allocfailure;
786 }
787 *(int *)datap->b_wptr = upper->kbtrans_streams_translate_mode;
788 datap->b_wptr += sizeof (int);
789 if (mp->b_cont) /* free msg to prevent memory leak */
790 freemsg(mp->b_cont);
791 mp->b_cont = datap;
792 iocp->ioc_count = sizeof (int);
793 break;
794
795 case VUIDSADDR:
796 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDSADDR\n"));
797
798 err = miocpullup(mp, sizeof (Vuid_addr_probe));
799 if (err != 0)
800 break;
801 addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
802 switch (addr_probe->base) {
803
804 case ASCII_FIRST:
805 addr_ptr = &upper->kbtrans_streams_vuid_addr.ascii;
806 break;
807
808 case TOP_FIRST:
809 addr_ptr = &upper->kbtrans_streams_vuid_addr.top;
810 break;
811
812 case VKEY_FIRST:
813 addr_ptr = &upper->kbtrans_streams_vuid_addr.vkey;
814 break;
815
816 default:
817 err = ENODEV;
818 }
819
820 if ((err == 0) && (*addr_ptr != addr_probe->data.next)) {
821 *addr_ptr = addr_probe->data.next;
822 kbtrans_flush(upper);
823 }
824 break;
825
826 case VUIDGADDR:
827 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "VUIDGADDR\n"));
828
829 err = miocpullup(mp, sizeof (Vuid_addr_probe));
830 if (err != 0)
831 break;
832 addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
833 switch (addr_probe->base) {
834
835 case ASCII_FIRST:
836 addr_probe->data.current =
837 upper->kbtrans_streams_vuid_addr.ascii;
838 break;
839
840 case TOP_FIRST:
841 addr_probe->data.current =
842 upper->kbtrans_streams_vuid_addr.top;
843 break;
844
845 case VKEY_FIRST:
846 addr_probe->data.current =
847 upper->kbtrans_streams_vuid_addr.vkey;
848 break;
849
850 default:
851 err = ENODEV;
852 }
853 break;
854
855 case KIOCTRANSABLE:
856 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCTRANSABLE\n"));
857
858 err = miocpullup(mp, sizeof (int));
859 if (err != 0)
860 break;
861 /*
862 * called during console setup in kbconfig()
863 * If set to false, means we are a serial keyboard,
864 * and we should pass all data up without modification.
865 */
866 translate = *(int *)mp->b_cont->b_rptr;
867 if (upper->kbtrans_streams_translatable != translate)
868 upper->kbtrans_streams_translatable = translate;
869
870 if (translate != TR_CAN)
871 DPRINTF(PRINT_L4, PRINT_MASK_ALL, (upper,
872 "Cannot translate keyboard using tables.\n"));
873 break;
874
875 case KIOCGTRANSABLE:
876 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGTRANSABLE\n"));
877 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
878 ioctlrespsize = sizeof (int);
879 goto allocfailure;
880 }
881 *(int *)datap->b_wptr = upper->kbtrans_streams_translatable;
882 datap->b_wptr += sizeof (int);
883 if (mp->b_cont) /* free msg to prevent memory leak */
884 freemsg(mp->b_cont);
885 mp->b_cont = datap;
886 iocp->ioc_count = sizeof (int);
887 break;
888
889 case KIOCSCOMPAT:
890 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSCOMPAT\n"));
891
892 err = miocpullup(mp, sizeof (int));
893 if (err != 0)
894 break;
895 lower->kbtrans_compat = *(int *)mp->b_cont->b_rptr;
896 break;
897
898 case KIOCGCOMPAT:
899 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGCOMPAT\n"));
900 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
901 ioctlrespsize = sizeof (int);
902 goto allocfailure;
903 }
904 *(int *)datap->b_wptr = lower->kbtrans_compat;
905 datap->b_wptr += sizeof (int);
906 if (mp->b_cont) /* free msg to prevent memory leak */
907 freemsg(mp->b_cont);
908 mp->b_cont = datap;
909 iocp->ioc_count = sizeof (int);
910 break;
911
912 case KIOCSETKEY:
913 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSETKEY %d\n",
914 kiocsetkey++));
915 err = miocpullup(mp, sizeof (struct kiockey));
916 if (err != 0)
917 break;
918 err = kbtrans_setkey(&upper->kbtrans_lower,
919 (struct kiockey *)mp->b_cont->b_rptr, iocp->ioc_cr);
920 /*
921 * Since this only affects any subsequent key presses,
922 * don't flush soft state. One might want to
923 * toggle the keytable entries dynamically.
924 */
925 break;
926
927 case KIOCGETKEY:
928 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGETKEY %d\n",
929 kiocgetkey++));
930 err = miocpullup(mp, sizeof (struct kiockey));
931 if (err != 0)
932 break;
933 err = kbtrans_getkey(&upper->kbtrans_lower,
934 (struct kiockey *)mp->b_cont->b_rptr);
935 break;
936
937 case KIOCSKEY:
938 err = miocpullup(mp, sizeof (struct kiockeymap));
939 if (err != 0)
940 break;
941 err = kbtrans_skey(&upper->kbtrans_lower,
942 (struct kiockeymap *)mp->b_cont->b_rptr, iocp->ioc_cr);
943 /*
944 * Since this only affects any subsequent key presses,
945 * don't flush soft state. One might want to
946 * toggle the keytable entries dynamically.
947 */
948 break;
949
950 case KIOCGKEY:
951 err = miocpullup(mp, sizeof (struct kiockeymap));
952 if (err != 0)
953 break;
954 err = kbtrans_gkey(&upper->kbtrans_lower,
955 (struct kiockeymap *)mp->b_cont->b_rptr);
956 break;
957
958 case KIOCSDIRECT:
959 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSDIRECT\n"));
960 kbtrans_flush(upper);
961 break;
962
963 case KIOCGDIRECT:
964 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSGDIRECT\n"));
965 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
966 ioctlrespsize = sizeof (int);
967 goto allocfailure;
968 }
969 *(int *)datap->b_wptr = 1; /* always direct */
970 datap->b_wptr += sizeof (int);
971 if (mp->b_cont) /* free msg to prevent memory leak */
972 freemsg(mp->b_cont);
973 mp->b_cont = datap;
974 iocp->ioc_count = sizeof (int);
975 break;
976
977 case KIOCTYPE:
978 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCTYPE\n"));
979 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
980 ioctlrespsize = sizeof (int);
981 goto allocfailure;
982 }
983 *(int *)datap->b_wptr = upper->kbtrans_streams_id;
984 datap->b_wptr += sizeof (int);
985 if (mp->b_cont) /* free msg to prevent memory leak */
986 freemsg(mp->b_cont);
987 mp->b_cont = datap;
988 iocp->ioc_count = sizeof (int);
989 break;
990
991 case CONSSETABORTENABLE:
992 /*
993 * Peek as it goes by; must be a TRANSPARENT ioctl.
994 */
995 if (iocp->ioc_count != TRANSPARENT) {
996 err = EINVAL;
997 break;
998 }
999
1000 upper->kbtrans_streams_abortable =
1001 (boolean_t)*(intptr_t *)mp->b_cont->b_rptr;
1002
1003 /*
1004 * Let the hardware module see it too.
1005 */
1006 return (KBTRANS_MESSAGE_NOT_HANDLED);
1007
1008 case KIOCGRPTCOUNT:
1009 /*
1010 * Report the autorepeat count
1011 */
1012 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGRPTCOUNT\n"));
1013 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1014 ioctlrespsize = sizeof (int);
1015 goto allocfailure;
1016 }
1017 *(int *)datap->b_wptr = kbtrans_repeat_count;
1018 datap->b_wptr += sizeof (int);
1019
1020 /* free msg to prevent memory leak */
1021 if (mp->b_cont != NULL)
1022 freemsg(mp->b_cont);
1023 mp->b_cont = datap;
1024 iocp->ioc_count = sizeof (int);
1025 break;
1026
1027 case KIOCSRPTCOUNT:
1028 /*
1029 * Set the autorepeat count
1030 */
1031 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSRPTCOUNT\n"));
1032 err = miocpullup(mp, sizeof (int));
1033
1034 if (err != 0)
1035 break;
1036
1037 /* validate the input */
1038 if (*(int *)mp->b_cont->b_rptr < -1) {
1039 err = EINVAL;
1040 break;
1041 }
1042 kbtrans_repeat_count = (*(int *)mp->b_cont->b_rptr);
1043 break;
1044
1045 case KIOCGRPTDELAY:
1046 /*
1047 * Report the autorepeat delay, unit in millisecond
1048 */
1049 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGRPTDELAY\n"));
1050 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1051 ioctlrespsize = sizeof (int);
1052 goto allocfailure;
1053 }
1054 *(int *)datap->b_wptr = TICK_TO_MSEC(kbtrans_repeat_delay);
1055 datap->b_wptr += sizeof (int);
1056
1057 /* free msg to prevent memory leak */
1058 if (mp->b_cont != NULL)
1059 freemsg(mp->b_cont);
1060 mp->b_cont = datap;
1061 iocp->ioc_count = sizeof (int);
1062 break;
1063
1064 case KIOCSRPTDELAY:
1065 /*
1066 * Set the autorepeat delay
1067 */
1068 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSRPTDELAY\n"));
1069 err = miocpullup(mp, sizeof (int));
1070
1071 if (err != 0)
1072 break;
1073
1074 /* validate the input */
1075 if (*(int *)mp->b_cont->b_rptr < KIOCRPTDELAY_MIN) {
1076 err = EINVAL;
1077 break;
1078 }
1079 kbtrans_repeat_delay = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
1080 if (kbtrans_repeat_delay <= 0)
1081 kbtrans_repeat_delay = 1;
1082 break;
1083
1084 case KIOCGRPTRATE:
1085 /*
1086 * Report the autorepeat rate
1087 */
1088 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCGRPTRATE\n"));
1089 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1090 ioctlrespsize = sizeof (int);
1091 goto allocfailure;
1092 }
1093 *(int *)datap->b_wptr = TICK_TO_MSEC(kbtrans_repeat_rate);
1094 datap->b_wptr += sizeof (int);
1095
1096 /* free msg to prevent memory leak */
1097 if (mp->b_cont != NULL)
1098 freemsg(mp->b_cont);
1099 mp->b_cont = datap;
1100 iocp->ioc_count = sizeof (int);
1101 break;
1102
1103 case KIOCSRPTRATE:
1104 /*
1105 * Set the autorepeat rate
1106 */
1107 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "KIOCSRPTRATE\n"));
1108 err = miocpullup(mp, sizeof (int));
1109
1110 if (err != 0)
1111 break;
1112
1113 /* validate the input */
1114 if (*(int *)mp->b_cont->b_rptr < KIOCRPTRATE_MIN) {
1115 err = EINVAL;
1116 break;
1117 }
1118 kbtrans_repeat_rate = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
1119 if (kbtrans_repeat_rate <= 0)
1120 kbtrans_repeat_rate = 1;
1121 break;
1122
1123 default:
1124 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (upper, "unknown\n"));
1125 return (KBTRANS_MESSAGE_NOT_HANDLED);
1126 } /* end switch */
1127
1128 if (err != 0) {
1129 iocp->ioc_rval = 0;
1130 iocp->ioc_error = err;
1131 mp->b_datap->db_type = M_IOCNAK;
1132 } else {
1133 iocp->ioc_rval = 0;
1134 iocp->ioc_error = 0; /* brain rot */
1135 mp->b_datap->db_type = M_IOCACK;
1136 }
1137 putnext(upper->kbtrans_streams_readq, mp);
1138
1139 return (KBTRANS_MESSAGE_HANDLED);
1140
1141 allocfailure:
1142 /*
1143 * We needed to allocate something to handle this "ioctl", but
1144 * couldn't; save this "ioctl" and arrange to get called back when
1145 * it's more likely that we can get what we need.
1146 * If there's already one being saved, throw it out, since it
1147 * must have timed out.
1148 */
1149 if (upper->kbtrans_streams_iocpending != NULL)
1150 freemsg(upper->kbtrans_streams_iocpending);
1151 upper->kbtrans_streams_iocpending = mp;
1152 if (upper->kbtrans_streams_bufcallid) {
1153 qunbufcall(upper->kbtrans_streams_readq,
1154 upper->kbtrans_streams_bufcallid);
1155 }
1156 upper->kbtrans_streams_bufcallid =
1157 qbufcall(upper->kbtrans_streams_readq, ioctlrespsize, BPRI_HI,
1158 kbtrans_reioctl, upper);
1159 /*
1160 * This is a white lie... we *will* handle it, eventually.
1161 */
1162 return (KBTRANS_MESSAGE_HANDLED);
1163 }
1164
1165 /*
1166 * kbtrans_flush:
1167 * Flush data upstream
1168 */
1169 static void
kbtrans_flush(register struct kbtrans * upper)1170 kbtrans_flush(register struct kbtrans *upper)
1171 {
1172 register queue_t *q;
1173
1174 /* Flush pending data already sent upstream */
1175 if ((q = upper->kbtrans_streams_readq) != NULL && q->q_next != NULL)
1176 (void) putnextctl1(q, M_FLUSH, FLUSHR);
1177
1178 /* Flush pending ups */
1179 bzero(upper->kbtrans_streams_downs, upper->kbtrans_streams_downs_bytes);
1180
1181 kbtrans_cancelrpt(upper);
1182 }
1183
1184 /*
1185 * kbtrans_setled:
1186 * Update the keyboard LEDs to match the current keyboard state.
1187 */
1188 static void
kbtrans_setled(struct kbtrans * upper)1189 kbtrans_setled(struct kbtrans *upper)
1190 {
1191 upper->kbtrans_streams_hw_callbacks->kbtrans_streams_setled(
1192 upper->kbtrans_streams_hw,
1193 upper->kbtrans_lower.kbtrans_led_state);
1194 }
1195
1196 /*
1197 * kbtrans_rpt:
1198 * If a key is held down, this function is set up to be called
1199 * after kbtrans_repeat_rate time elapses.
1200 */
1201 static void
kbtrans_rpt(void * arg)1202 kbtrans_rpt(void *arg)
1203 {
1204 struct kbtrans *upper = arg;
1205 struct kbtrans_lower *lower = &upper->kbtrans_lower;
1206
1207 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL,
1208 "kbtrans_rpt: repeat key %X\n",
1209 lower->kbtrans_repeatkey));
1210
1211 upper->kbtrans_streams_rptid = 0;
1212 upper->kbtrans_streams_count++;
1213
1214 /*
1215 * NB: polled code zaps kbtrans_repeatkey without cancelling
1216 * timeout.
1217 */
1218 if (kbtrans_repeat_count > 0) {
1219 /* If limit is set and reached, stop there. */
1220 if (upper->kbtrans_streams_count > kbtrans_repeat_count)
1221 lower->kbtrans_repeatkey = 0;
1222 }
1223
1224 if (lower->kbtrans_repeatkey != 0) {
1225 kbtrans_keyreleased(upper, lower->kbtrans_repeatkey);
1226
1227 kbtrans_processkey(lower,
1228 upper->kbtrans_streams_callback,
1229 lower->kbtrans_repeatkey,
1230 KEY_PRESSED);
1231
1232 upper->kbtrans_streams_rptid =
1233 qtimeout(upper->kbtrans_streams_readq, kbtrans_rpt,
1234 (caddr_t)upper, kbtrans_repeat_rate);
1235 }
1236 }
1237
1238 /*
1239 * kbtrans_cancelrpt:
1240 * Cancel the repeating key
1241 */
1242 static void
kbtrans_cancelrpt(struct kbtrans * upper)1243 kbtrans_cancelrpt(struct kbtrans *upper)
1244 {
1245 upper->kbtrans_lower.kbtrans_repeatkey = 0;
1246
1247 if (upper->kbtrans_streams_rptid != 0) {
1248 (void) quntimeout(upper->kbtrans_streams_readq,
1249 upper->kbtrans_streams_rptid);
1250 upper->kbtrans_streams_rptid = 0;
1251 }
1252 }
1253
1254 /*
1255 * kbtrans_send_esc_event:
1256 * Send character up stream. Used for the case of
1257 * sending strings upstream.
1258 */
1259 static void
kbtrans_send_esc_event(char c,register struct kbtrans * upper)1260 kbtrans_send_esc_event(char c, register struct kbtrans *upper)
1261 {
1262 Firm_event fe;
1263
1264 fe.id = c;
1265 fe.value = 1;
1266 fe.pair_type = FE_PAIR_NONE;
1267 fe.pair = 0;
1268 /*
1269 * Pretend as if each cp pushed and released
1270 * Calling kbtrans_queueevent avoids addr translation
1271 * and pair base determination of kbtrans_keypressed.
1272 */
1273 kbtrans_queueevent(upper, &fe);
1274 fe.value = 0;
1275 kbtrans_queueevent(upper, &fe);
1276 }
1277
1278 /*
1279 * kbtrans_strsetwithdecimal:
1280 * Used for expanding a function key to the ascii equivalent
1281 */
1282 static char *
kbtrans_strsetwithdecimal(char * buf,uint_t val,uint_t maxdigs)1283 kbtrans_strsetwithdecimal(char *buf, uint_t val, uint_t maxdigs)
1284 {
1285 int hradix = 5;
1286 char *bp;
1287 int lowbit;
1288 char *tab = "0123456789abcdef";
1289
1290 bp = buf + maxdigs;
1291 *(--bp) = '\0';
1292 while (val) {
1293 lowbit = val & 1;
1294 val = (val >> 1);
1295 *(--bp) = tab[val % hradix * 2 + lowbit];
1296 val /= hradix;
1297 }
1298 return (bp);
1299 }
1300
1301 /*
1302 * kbtrans_keypressed:
1303 * Modify Firm event to be sent up the stream
1304 */
1305 static void
kbtrans_keypressed(struct kbtrans * upper,uchar_t key_station,Firm_event * fe,ushort_t base)1306 kbtrans_keypressed(struct kbtrans *upper, uchar_t key_station,
1307 Firm_event *fe, ushort_t base)
1308 {
1309
1310 register short id_addr;
1311 struct kbtrans_lower *lower = &upper->kbtrans_lower;
1312
1313 /* Set pair values */
1314 if (fe->id < (ushort_t)VKEY_FIRST) {
1315 /*
1316 * If CTRLed, find the ID that would have been used had it
1317 * not been CTRLed.
1318 */
1319 if (lower->kbtrans_shiftmask & (CTRLMASK | CTLSMASK)) {
1320 keymap_entry_t *ke;
1321 unsigned int mask;
1322
1323 mask = lower->kbtrans_shiftmask &
1324 ~(CTRLMASK | CTLSMASK | UPMASK);
1325
1326 ke = kbtrans_find_entry(lower, mask, key_station);
1327 if (ke == NULL)
1328 return;
1329
1330 base = *ke;
1331 }
1332 if (base != fe->id) {
1333 fe->pair_type = FE_PAIR_SET;
1334 fe->pair = (uchar_t)base;
1335
1336 goto send;
1337 }
1338 }
1339 fe->pair_type = FE_PAIR_NONE;
1340 fe->pair = 0;
1341
1342 send:
1343 /* Adjust event id address for multiple keyboard/workstation support */
1344 switch (vuid_id_addr(fe->id)) {
1345 case ASCII_FIRST:
1346 id_addr = upper->kbtrans_streams_vuid_addr.ascii;
1347 break;
1348 case TOP_FIRST:
1349 id_addr = upper->kbtrans_streams_vuid_addr.top;
1350 break;
1351 case VKEY_FIRST:
1352 id_addr = upper->kbtrans_streams_vuid_addr.vkey;
1353 break;
1354 default:
1355 id_addr = vuid_id_addr(fe->id);
1356 break;
1357 }
1358 fe->id = vuid_id_offset(fe->id) | id_addr;
1359
1360 kbtrans_queuepress(upper, key_station, fe);
1361 }
1362
1363 /*
1364 * kbtrans_queuepress:
1365 * Add keypress to the "downs" table
1366 */
1367 static void
kbtrans_queuepress(struct kbtrans * upper,uchar_t key_station,Firm_event * fe)1368 kbtrans_queuepress(struct kbtrans *upper,
1369 uchar_t key_station, Firm_event *fe)
1370 {
1371 register struct key_event *ke, *ke_free;
1372 register int i;
1373
1374 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL, "kbtrans_queuepress:"
1375 " key=%d", key_station));
1376
1377 ke_free = 0;
1378
1379 /* Scan table of down key stations */
1380
1381 for (i = 0, ke = upper->kbtrans_streams_downs;
1382 i < upper->kbtrans_streams_num_downs_entries; i++, ke++) {
1383
1384 /* Keycode already down? */
1385 if (ke->key_station == key_station) {
1386
1387 DPRINTF(PRINT_L0, PRINT_MASK_ALL,
1388 (NULL, "kbtrans: Double "
1389 "entry in downs table (%d,%d)!\n",
1390 key_station, i));
1391
1392 goto add_event;
1393 }
1394
1395 if (ke->key_station == 0)
1396 ke_free = ke;
1397 }
1398
1399 if (ke_free) {
1400 ke = ke_free;
1401 goto add_event;
1402 }
1403
1404 ke = upper->kbtrans_streams_downs;
1405
1406 add_event:
1407 ke->key_station = key_station;
1408 ke->event = *fe;
1409 kbtrans_queueevent(upper, fe);
1410 }
1411
1412 /*
1413 * kbtrans_keyreleased:
1414 * Remove entry from the downs table
1415 */
1416 static void
kbtrans_keyreleased(register struct kbtrans * upper,uchar_t key_station)1417 kbtrans_keyreleased(register struct kbtrans *upper, uchar_t key_station)
1418 {
1419 register struct key_event *ke;
1420 register int i;
1421
1422 DPRINTF(PRINT_L0, PRINT_MASK_ALL, (NULL, "RELEASE key=%d\n",
1423 key_station));
1424
1425 if (upper->kbtrans_streams_translate_mode != TR_EVENT &&
1426 upper->kbtrans_streams_translate_mode != TR_UNTRANS_EVENT) {
1427
1428 return;
1429 }
1430
1431 /* Scan table of down key stations */
1432 for (i = 0, ke = upper->kbtrans_streams_downs;
1433 i < upper->kbtrans_streams_num_downs_entries;
1434 i++, ke++) {
1435 /* Found? */
1436 if (ke->key_station == key_station) {
1437 ke->key_station = 0;
1438 ke->event.value = 0;
1439 kbtrans_queueevent(upper, &ke->event);
1440 }
1441 }
1442
1443 /*
1444 * Ignore if couldn't find because may be called twice
1445 * for the same key station in the case of the kbtrans_rpt
1446 * routine being called unnecessarily.
1447 */
1448 }
1449
1450
1451 /*
1452 * kbtrans_putcode:
1453 * Pass a keycode up the stream, if you can, otherwise throw it away.
1454 */
1455 static void
kbtrans_putcode(register struct kbtrans * upper,uint_t code)1456 kbtrans_putcode(register struct kbtrans *upper, uint_t code)
1457 {
1458 register mblk_t *bp;
1459
1460 /*
1461 * If we can't send it up, then we just drop it.
1462 */
1463 if (!canputnext(upper->kbtrans_streams_readq)) {
1464
1465 return;
1466 }
1467
1468 /*
1469 * Allocate a messsage block to send up.
1470 */
1471 if ((bp = allocb(sizeof (uint_t), BPRI_HI)) == NULL) {
1472
1473 cmn_err(CE_WARN, "kbtrans_putcode: "
1474 "Can't allocate block for keycode.");
1475
1476 return;
1477 }
1478
1479 /*
1480 * We will strip out any high order information here.
1481 * Convert to UTF-8.
1482 */
1483 code = KEYCHAR(code);
1484 if (code < 0x80) {
1485 *bp->b_wptr++ = (char)code;
1486 } else if (code < 0x800) {
1487 *bp->b_wptr++ = 0xc0 | (code >> 6);
1488 *bp->b_wptr++ = 0x80 | (code & 0x3f);
1489 } else if (code < 0x10000) {
1490 *bp->b_wptr++ = 0xe0 | (code >> 12);
1491 *bp->b_wptr++ = 0x80 | ((code >> 6) & 0x3f);
1492 *bp->b_wptr++ = 0x80 | (code & 0x3f);
1493 } else {
1494 *bp->b_wptr++ = 0xf0 | (code >> 18);
1495 *bp->b_wptr++ = 0x80 | ((code >> 12) & 0x3f);
1496 *bp->b_wptr++ = 0x80 | ((code >> 6) & 0x3f);
1497 *bp->b_wptr++ = 0x80 | (code & 0x3f);
1498 }
1499
1500 /*
1501 * Send the message up.
1502 */
1503 (void) putnext(upper->kbtrans_streams_readq, bp);
1504 }
1505
1506
1507 /*
1508 * kbtrans_putbuf:
1509 * Pass generated keycode sequence to upstream, if possible.
1510 */
1511 static void
kbtrans_putbuf(char * buf,queue_t * q)1512 kbtrans_putbuf(char *buf, queue_t *q)
1513 {
1514 register mblk_t *bp;
1515
1516 if (!canputnext(q)) {
1517 cmn_err(CE_WARN, "kbtrans_putbuf: Can't put block for keycode");
1518 } else {
1519 if ((bp = allocb((int)strlen(buf), BPRI_HI)) == NULL) {
1520 cmn_err(CE_WARN, "kbtrans_putbuf: "
1521 "Can't allocate block for keycode");
1522 } else {
1523 while (*buf) {
1524 *bp->b_wptr++ = *buf;
1525 buf++;
1526 }
1527 putnext(q, bp);
1528 }
1529 }
1530 }
1531
1532 /*
1533 * kbtrans_queueevent:
1534 * Pass a VUID "firm event" up the stream, if you can.
1535 */
1536 static void
kbtrans_queueevent(struct kbtrans * upper,Firm_event * fe)1537 kbtrans_queueevent(struct kbtrans *upper, Firm_event *fe)
1538 {
1539 register queue_t *q;
1540 register mblk_t *bp;
1541
1542 if ((q = upper->kbtrans_streams_readq) == NULL)
1543
1544 return;
1545
1546 if (!canputnext(q)) {
1547 if (kbtrans_overflow_msg) {
1548 DPRINTF(PRINT_L2, PRINT_MASK_ALL, (NULL,
1549 "kbtrans: Buffer flushed when overflowed."));
1550 }
1551
1552 kbtrans_flush(upper);
1553 upper->kbtrans_overflow_cnt++;
1554 } else {
1555 if ((bp = allocb(sizeof (Firm_event), BPRI_HI)) == NULL) {
1556 cmn_err(CE_WARN, "kbtrans_queueevent: "
1557 "Can't allocate block for event.");
1558 } else {
1559 uniqtime32(&fe->time);
1560 *(Firm_event *)bp->b_wptr = *fe;
1561 bp->b_wptr += sizeof (Firm_event);
1562 (void) putnext(q, bp);
1563
1564
1565 }
1566 }
1567 }
1568
1569 /*
1570 * kbtrans_set_translation_callback:
1571 * This code sets the translation_callback pointer based on the
1572 * translation mode.
1573 */
1574 static void
kbtrans_set_translation_callback(register struct kbtrans * upper)1575 kbtrans_set_translation_callback(register struct kbtrans *upper)
1576 {
1577 switch (upper->kbtrans_streams_translate_mode) {
1578
1579 default:
1580 case TR_ASCII:
1581 upper->vt_switch_keystate = VT_SWITCH_KEY_NONE;
1582
1583 /* Discard any obsolete CTRL/ALT/SHIFT keys */
1584 upper->kbtrans_lower.kbtrans_shiftmask &=
1585 ~(CTRLMASK | ALTMASK | SHIFTMASK);
1586 upper->kbtrans_lower.kbtrans_togglemask &=
1587 ~(CTRLMASK | ALTMASK | SHIFTMASK);
1588
1589 upper->kbtrans_streams_callback = &ascii_callback;
1590
1591 break;
1592
1593 case TR_EVENT:
1594 upper->kbtrans_streams_callback = &trans_event_callback;
1595
1596 break;
1597
1598 case TR_UNTRANS_EVENT:
1599 upper->kbtrans_streams_callback = &untrans_event_callback;
1600
1601 break;
1602 }
1603 }
1604
1605 /*
1606 * kbtrans_untrans_keypressed_raw:
1607 * This is the callback we get if we are in TR_UNTRANS_EVENT and a
1608 * key is pressed. This code will just send the scancode up the
1609 * stream.
1610 */
1611 static void
kbtrans_untrans_keypressed_raw(struct kbtrans * upper,kbtrans_key_t key)1612 kbtrans_untrans_keypressed_raw(struct kbtrans *upper, kbtrans_key_t key)
1613 {
1614 Firm_event fe;
1615
1616 bzero(&fe, sizeof (fe));
1617
1618 /*
1619 * fill in the event
1620 */
1621 fe.id = (unsigned short)key;
1622 fe.value = 1;
1623
1624 /*
1625 * Send the event upstream.
1626 */
1627 kbtrans_queuepress(upper, key, &fe);
1628 }
1629
1630 /*
1631 * kbtrans_untrans_keyreleased_raw:
1632 * This is the callback we get if we are in TR_UNTRANS_EVENT mode
1633 * and a key is released. This code will just send the scancode up
1634 * the stream.
1635 */
1636 static void
kbtrans_untrans_keyreleased_raw(struct kbtrans * upper,kbtrans_key_t key)1637 kbtrans_untrans_keyreleased_raw(struct kbtrans *upper, kbtrans_key_t key)
1638 {
1639 /*
1640 * Deal with a key released event.
1641 */
1642 kbtrans_keyreleased(upper, key);
1643 }
1644
1645 /*
1646 * kbtrans_vt_compose:
1647 * To compose the key sequences for virtual terminal switching.
1648 *
1649 * 'ALTL + F#' for 1-12 terminals
1650 * 'ALTGR + F#' for 13-24 terminals
1651 * 'ALT + UPARROW' for last terminal
1652 * 'ALT + LEFTARROW' for previous terminal
1653 * 'ALT + RIGHTARROW' for next terminal
1654 *
1655 * the vt switching message is encoded as:
1656 *
1657 * -------------------------------------------------------------
1658 * | \033 | 'Q' | vtno + 'A' | opcode | 'z' | '\0' |
1659 * -------------------------------------------------------------
1660 *
1661 * opcode:
1662 * 'B' to switch to previous terminal
1663 * 'F' to switch to next terminal
1664 * 'L' to switch to last terminal
1665 * 'H' to switch to the terminal as specified by vtno,
1666 * which is from 1 to 24.
1667 *
1668 * Here keyid is the keycode of UPARROW, LEFTARROW, or RIGHTARROW
1669 * when it is a kind of arrow key as indicated by is_arrow_key,
1670 * otherwise it indicates a function key and keyid is the number
1671 * corresponding to that function key.
1672 */
1673 static void
kbtrans_vt_compose(struct kbtrans * upper,unsigned short keyid,boolean_t is_arrow_key,char * buf)1674 kbtrans_vt_compose(struct kbtrans *upper, unsigned short keyid,
1675 boolean_t is_arrow_key, char *buf)
1676 {
1677 char *bufp;
1678
1679 bufp = buf;
1680 *bufp++ = '\033'; /* Escape */
1681 *bufp++ = 'Q';
1682 if (is_arrow_key) {
1683 *bufp++ = 'A';
1684 switch (keyid) {
1685 case UPARROW: /* last vt */
1686 *bufp++ = 'L';
1687 break;
1688 case LEFTARROW: /* previous vt */
1689 *bufp++ = 'B';
1690 break;
1691 case RIGHTARROW: /* next vt */
1692 *bufp++ = 'F';
1693 break;
1694 default:
1695 break;
1696 }
1697 } else {
1698 /* this is funckey specifying vtno for switch */
1699 *bufp++ = keyid +
1700 (upper->vt_switch_keystate - VT_SWITCH_KEY_ALT) *
1701 KB_NR_FUNCKEYS + 'A';
1702 *bufp++ = 'H';
1703 }
1704 *bufp++ = 'z';
1705 *bufp = '\0';
1706
1707 /*
1708 * Send the result upstream.
1709 */
1710 kbtrans_putbuf(buf, upper->kbtrans_streams_readq);
1711
1712 }
1713
1714 /*
1715 * kbtrans_ascii_keypressed:
1716 * This is the code if we are in TR_ASCII mode and a key
1717 * is pressed. This is where we will do any special processing that
1718 * is specific to ASCII key translation.
1719 */
1720 /* ARGSUSED */
1721 static void
kbtrans_ascii_keypressed(struct kbtrans * upper,uint_t entrytype,kbtrans_key_t key,uint_t entry)1722 kbtrans_ascii_keypressed(struct kbtrans *upper, uint_t entrytype,
1723 kbtrans_key_t key, uint_t entry)
1724 {
1725 register char *cp;
1726 register char *bufp;
1727 char buf[14];
1728 unsigned short keyid;
1729 struct kbtrans_lower *lower = &upper->kbtrans_lower;
1730
1731 /*
1732 * Based on the type of key, we may need to do some ASCII
1733 * specific post processing. Note that the translated entry
1734 * is constructed as the actual keycode plus entrytype. See
1735 * sys/kbd.h for details of each entrytype.
1736 */
1737 switch (entrytype) {
1738 case BUCKYBITS:
1739 return;
1740
1741 case SHIFTKEYS:
1742 keyid = entry & 0xFF;
1743 if (keyid == ALT) {
1744 upper->vt_switch_keystate = VT_SWITCH_KEY_ALT;
1745 } else if (keyid == ALTGRAPH) {
1746 upper->vt_switch_keystate = VT_SWITCH_KEY_ALTGR;
1747 }
1748 return;
1749
1750 case FUNNY:
1751 /*
1752 * There is no ascii equivalent. We will ignore these
1753 * keys
1754 */
1755 return;
1756
1757 case FUNCKEYS:
1758 if (upper->vt_switch_keystate > VT_SWITCH_KEY_NONE) {
1759 if (entry >= TOPFUNC &&
1760 entry < (TOPFUNC + KB_NR_FUNCKEYS)) {
1761
1762 /*
1763 * keyid is the number correspoding to F#
1764 * and its value is from 1 to 12.
1765 */
1766 keyid = (entry & 0xF) + 1;
1767
1768 kbtrans_vt_compose(upper, keyid, B_FALSE, buf);
1769 return;
1770 }
1771 }
1772
1773 if (kbtrans_ignore_scroll_lock && entry == RF(3)) {
1774 /*
1775 * We do not perform full handling of the "Scroll Lock"
1776 * key. It does not change the console scrolling mode
1777 * or even impact the keyboard indicator light.
1778 *
1779 * Some hypervisor keyboard emulators (e.g., SPICE in
1780 * QEMU) seek to keep the scroll lock state in sync
1781 * with the local client keyboard state by aggressively
1782 * generating emulated Scroll Lock press and release
1783 * events. Emitting the function key control sequence
1784 * (which is already of dubious utility) makes the
1785 * console unusable; instead, we ignore Scroll Lock
1786 * completely here.
1787 */
1788 return;
1789 }
1790
1791 /*
1792 * We need to expand this key to get the ascii
1793 * equivalent. These are the function keys (F1, F2 ...)
1794 */
1795 bufp = buf;
1796 cp = kbtrans_strsetwithdecimal(bufp + 2,
1797 (uint_t)((entry & 0x003F) + 192),
1798 sizeof (buf) - 5);
1799 *bufp++ = '\033'; /* Escape */
1800 *bufp++ = '[';
1801 while (*cp != '\0')
1802 *bufp++ = *cp++;
1803 *bufp++ = 'z';
1804 *bufp = '\0';
1805
1806 /*
1807 * Send the result upstream.
1808 */
1809 kbtrans_putbuf(buf, upper->kbtrans_streams_readq);
1810
1811 return;
1812
1813 case STRING:
1814 if (upper->vt_switch_keystate > VT_SWITCH_KEY_NONE) {
1815 keyid = entry & 0xFF;
1816 if (keyid == UPARROW ||
1817 keyid == RIGHTARROW ||
1818 keyid == LEFTARROW) {
1819
1820 kbtrans_vt_compose(upper, keyid, B_TRUE, buf);
1821 return;
1822 }
1823 }
1824
1825 /*
1826 * These are the multi byte keys (Home, Up, Down ...)
1827 */
1828 cp = &lower->kbtrans_keystringtab[entry & 0x0F][0];
1829
1830 /*
1831 * Copy the string from the keystringtable, and send it
1832 * upstream a character at a time.
1833 */
1834 while (*cp != '\0') {
1835
1836 kbtrans_putcode(upper, (uchar_t)*cp);
1837
1838 cp++;
1839 }
1840
1841 return;
1842
1843 case PADKEYS:
1844 /*
1845 * These are the keys on the keypad. Look up the
1846 * answer in the kb_numlock_table and send it upstream.
1847 */
1848 kbtrans_putcode(upper,
1849 lower->kbtrans_numlock_table[entry&0x1F]);
1850
1851 return;
1852
1853 case 0: /* normal character */
1854 default:
1855 break;
1856 }
1857
1858 /*
1859 * Send the char upstream.
1860 */
1861 kbtrans_putcode(upper, entry);
1862
1863 }
1864
1865 #define KB_SCANCODE_ALT 0xe2
1866 #define KB_SCANCODE_ALTGRAPH 0xe6
1867
1868 /*
1869 * kbtrans_ascii_keyreleased:
1870 * This is the function if we are in TR_ASCII mode and a key
1871 * is released. ASCII doesn't have the concept of released keys,
1872 * or make/break codes. So there is nothing for us to do except
1873 * checking 'Alt/AltGraph' release key in order to reset the state
1874 * of vt switch key sequence.
1875 */
1876 /* ARGSUSED */
1877 static void
kbtrans_ascii_keyreleased(struct kbtrans * upper,kbtrans_key_t key)1878 kbtrans_ascii_keyreleased(struct kbtrans *upper, kbtrans_key_t key)
1879 {
1880 if (key == KB_SCANCODE_ALT || key == KB_SCANCODE_ALTGRAPH) {
1881 upper->vt_switch_keystate = VT_SWITCH_KEY_NONE;
1882 }
1883 }
1884
1885 /*
1886 * kbtrans_ascii_setup_repeat:
1887 * This is the function if we are in TR_ASCII mode and the
1888 * translation module has decided that a key needs to be repeated.
1889 */
1890 /* ARGSUSED */
1891 static void
kbtrans_ascii_setup_repeat(struct kbtrans * upper,uint_t entrytype,kbtrans_key_t key)1892 kbtrans_ascii_setup_repeat(struct kbtrans *upper, uint_t entrytype,
1893 kbtrans_key_t key)
1894 {
1895 struct kbtrans_lower *lower = &upper->kbtrans_lower;
1896
1897 /*
1898 * Cancel any currently repeating keys. This will be a new
1899 * key to repeat.
1900 */
1901 kbtrans_cancelrpt(upper);
1902
1903 /*
1904 * Set the value of the key to be repeated.
1905 */
1906 lower->kbtrans_repeatkey = key;
1907
1908 /*
1909 * Start the timeout for repeating this key. kbtrans_rpt will
1910 * be called to repeat the key.
1911 */
1912 upper->kbtrans_streams_count = 0;
1913 upper->kbtrans_streams_rptid = qtimeout(upper->kbtrans_streams_readq,
1914 kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
1915 }
1916
1917 /*
1918 * kbtrans_trans_event_keypressed:
1919 * This is the function if we are in TR_EVENT mode and a key
1920 * is pressed. This is where we will do any special processing that
1921 * is specific to EVENT key translation.
1922 */
1923 static void
kbtrans_trans_event_keypressed(struct kbtrans * upper,uint_t entrytype,kbtrans_key_t key,uint_t entry)1924 kbtrans_trans_event_keypressed(struct kbtrans *upper, uint_t entrytype,
1925 kbtrans_key_t key, uint_t entry)
1926 {
1927 Firm_event fe;
1928 register char *cp;
1929 struct kbtrans_lower *lower = &upper->kbtrans_lower;
1930
1931 /*
1932 * Based on the type of key, we may need to do some EVENT
1933 * specific post processing.
1934 */
1935 switch (entrytype) {
1936
1937 case SHIFTKEYS:
1938 /*
1939 * Relying on ordinal correspondence between
1940 * vuid_event.h SHIFT_META-SHIFT_TOP &
1941 * kbd.h METABIT-SYSTEMBIT in order to
1942 * correctly translate entry into fe.id.
1943 */
1944 fe.id = SHIFT_CAPSLOCK + (entry & 0x0F);
1945 fe.value = 1;
1946 kbtrans_keypressed(upper, key, &fe, fe.id);
1947
1948 return;
1949
1950 case BUCKYBITS:
1951 /*
1952 * Relying on ordinal correspondence between
1953 * vuid_event.h SHIFT_CAPSLOCK-SHIFT_RIGHTCTRL &
1954 * kbd.h CAPSLOCK-RIGHTCTRL in order to
1955 * correctly translate entry into fe.id.
1956 */
1957 fe.id = SHIFT_META + (entry & 0x0F);
1958 fe.value = 1;
1959 kbtrans_keypressed(upper, key, &fe, fe.id);
1960
1961 return;
1962
1963 case FUNCKEYS:
1964 /*
1965 * Take advantage of the similar
1966 * ordering of kbd.h function keys and
1967 * vuid_event.h function keys to do a
1968 * simple translation to achieve a
1969 * mapping between the 2 different
1970 * address spaces.
1971 */
1972 fe.id = KEY_LEFTFIRST + (entry & 0x003F);
1973 fe.value = 1;
1974
1975 /*
1976 * Assume "up" table only generates
1977 * shift changes.
1978 */
1979 kbtrans_keypressed(upper, key, &fe, fe.id);
1980
1981 /*
1982 * Function key events can be expanded
1983 * by terminal emulator software to
1984 * produce the standard escape sequence
1985 * generated by the TR_ASCII case above
1986 * if a function key event is not used
1987 * by terminal emulator software
1988 * directly.
1989 */
1990 return;
1991
1992 case STRING:
1993 /*
1994 * These are the multi byte keys (Home, Up, Down ...)
1995 */
1996 cp = &lower->kbtrans_keystringtab[entry & 0x0F][0];
1997
1998 /*
1999 * Copy the string from the keystringtable, and send it
2000 * upstream a character at a time.
2001 */
2002 while (*cp != '\0') {
2003
2004 kbtrans_send_esc_event(*cp, upper);
2005
2006 cp++;
2007 }
2008
2009 return;
2010
2011 case PADKEYS:
2012 /*
2013 * Take advantage of the similar
2014 * ordering of kbd.h keypad keys and
2015 * vuid_event.h keypad keys to do a
2016 * simple translation to achieve a
2017 * mapping between the 2 different
2018 * address spaces.
2019 */
2020 fe.id = VKEY_FIRSTPAD + (entry & 0x001F);
2021 fe.value = 1;
2022
2023 /*
2024 * Assume "up" table only generates
2025 * shift changes.
2026 */
2027 kbtrans_keypressed(upper, key, &fe, fe.id);
2028
2029 /*
2030 * Keypad key events can be expanded
2031 * by terminal emulator software to
2032 * produce the standard ascii character
2033 * generated by the TR_ASCII case above
2034 * if a keypad key event is not used
2035 * by terminal emulator software
2036 * directly.
2037 */
2038 return;
2039
2040 case FUNNY:
2041 /*
2042 * These are not events.
2043 */
2044 switch (entry) {
2045 case IDLE:
2046 case RESET:
2047 case ERROR:
2048 /*
2049 * Something has happened. Mark all keys as released.
2050 */
2051 kbtrans_streams_releaseall(upper);
2052 break;
2053 }
2054
2055 return;
2056
2057 case 0: /* normal character */
2058 default:
2059 break;
2060 }
2061
2062 /*
2063 * Send the event upstream.
2064 */
2065 fe.id = entry;
2066
2067 fe.value = 1;
2068
2069 kbtrans_queueevent(upper, &fe);
2070 }
2071
2072 /*
2073 * kbtrans_trans_event_keyreleased:
2074 * This is the function if we are in TR_EVENT mode and a key
2075 * is released.
2076 */
2077 /* ARGSUSED */
2078 static void
kbtrans_trans_event_keyreleased(struct kbtrans * upper,kbtrans_key_t key)2079 kbtrans_trans_event_keyreleased(struct kbtrans *upper, kbtrans_key_t key)
2080 {
2081 /*
2082 * Mark the key as released and send an event upstream.
2083 */
2084 kbtrans_keyreleased(upper, key);
2085 }
2086
2087 /*
2088 * kbtrans_trans_event_setup_repeat:
2089 * This is the function if we are in TR_EVENT mode and the
2090 * translation module has decided that a key needs to be repeated.
2091 * We will set a timeout to retranslate the repeat key.
2092 */
2093 static void
kbtrans_trans_event_setup_repeat(struct kbtrans * upper,uint_t entrytype,kbtrans_key_t key)2094 kbtrans_trans_event_setup_repeat(struct kbtrans *upper, uint_t entrytype,
2095 kbtrans_key_t key)
2096 {
2097 struct kbtrans_lower *lower = &upper->kbtrans_lower;
2098
2099 /*
2100 * Function keys and keypad keys do not repeat when we are in
2101 * EVENT mode.
2102 */
2103 if (entrytype == FUNCKEYS || entrytype == PADKEYS) {
2104
2105 return;
2106 }
2107
2108 /*
2109 * Cancel any currently repeating keys. This will be a new
2110 * key to repeat.
2111 */
2112 kbtrans_cancelrpt(upper);
2113
2114 /*
2115 * Set the value of the key to be repeated.
2116 */
2117 lower->kbtrans_repeatkey = key;
2118
2119 /*
2120 * Start the timeout for repeating this key. kbtrans_rpt will
2121 * be called to repeat the key.
2122 */
2123 upper->kbtrans_streams_count = 0;
2124 upper->kbtrans_streams_rptid = qtimeout(upper->kbtrans_streams_readq,
2125 kbtrans_rpt, (caddr_t)upper, kbtrans_repeat_delay);
2126 }
2127
2128 /*
2129 * Administer the key tables.
2130 */
2131
2132 /*
2133 * Old special codes.
2134 */
2135 #define OLD_SHIFTKEYS 0x80
2136 #define OLD_BUCKYBITS 0x90
2137 #define OLD_FUNNY 0xA0
2138 #define OLD_FA_UMLAUT 0xA9
2139 #define OLD_FA_CFLEX 0xAA
2140 #define OLD_FA_TILDE 0xAB
2141 #define OLD_FA_CEDILLA 0xAC
2142 #define OLD_FA_ACUTE 0xAD
2143 #define OLD_FA_GRAVE 0xAE
2144 #define OLD_ISOCHAR 0xAF
2145 #define OLD_STRING 0xB0
2146 #define OLD_LEFTFUNC 0xC0
2147 #define OLD_RIGHTFUNC 0xD0
2148 #define OLD_TOPFUNC 0xE0
2149 #define OLD_BOTTOMFUNC 0xF0
2150
2151 /*
2152 * Map old special codes to new ones.
2153 * Indexed by ((old special code) >> 4) & 0x07; add (old special code) & 0x0F.
2154 */
2155 static keymap_entry_t special_old_to_new[] = {
2156 SHIFTKEYS,
2157 BUCKYBITS,
2158 FUNNY,
2159 STRING,
2160 LEFTFUNC,
2161 RIGHTFUNC,
2162 TOPFUNC,
2163 BOTTOMFUNC,
2164 };
2165
2166
2167 /*
2168 * kbtrans_setkey:
2169 * Set individual keystation translation from old-style entry.
2170 */
2171 static int
kbtrans_setkey(struct kbtrans_lower * lower,struct kiockey * key,cred_t * cr)2172 kbtrans_setkey(struct kbtrans_lower *lower, struct kiockey *key, cred_t *cr)
2173 {
2174 int strtabindex, i;
2175 keymap_entry_t *ke;
2176 register int tablemask;
2177 register keymap_entry_t entry;
2178 register struct keyboard *kp;
2179
2180 kp = lower->kbtrans_keyboard;
2181
2182 if (key->kio_station >= kp->k_keymap_size)
2183 return (EINVAL);
2184
2185 if (lower->kbtrans_keyboard == NULL)
2186
2187 return (EINVAL);
2188
2189 tablemask = key->kio_tablemask;
2190
2191 switch (tablemask) {
2192 case KIOCABORT1:
2193 case KIOCABORT1A:
2194 case KIOCABORT2:
2195 i = secpolicy_console(cr);
2196 if (i != 0)
2197 return (i);
2198
2199 switch (tablemask) {
2200 case KIOCABORT1:
2201 kp->k_abort1 = key->kio_station;
2202 break;
2203 case KIOCABORT1A:
2204 kp->k_abort1a = key->kio_station;
2205 break;
2206 case KIOCABORT2:
2207 kp->k_abort2 = key->kio_station;
2208 break;
2209 }
2210 return (0);
2211 }
2212
2213 if (tablemask & ALTGRAPHMASK)
2214 return (EINVAL);
2215
2216 ke = kbtrans_find_entry(lower, (uint_t)tablemask, key->kio_station);
2217 if (ke == NULL)
2218 return (EINVAL);
2219
2220 if (key->kio_entry >= (uchar_t)OLD_STRING &&
2221 key->kio_entry <= (uchar_t)(OLD_STRING + 15)) {
2222 strtabindex = key->kio_entry - OLD_STRING;
2223 bcopy(key->kio_string,
2224 lower->kbtrans_keystringtab[strtabindex], KTAB_STRLEN);
2225 lower->kbtrans_keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
2226 }
2227
2228 entry = key->kio_entry;
2229
2230 /*
2231 * There's nothing we need do with OLD_ISOCHAR.
2232 */
2233 if (entry != OLD_ISOCHAR) {
2234 if (entry & 0x80) {
2235 if (entry >= OLD_FA_UMLAUT && entry <= OLD_FA_GRAVE)
2236 entry = FA_CLASS + (entry & 0x0F) - 9;
2237 else
2238 entry =
2239 special_old_to_new[entry >> 4 & 0x07]
2240 + (entry & 0x0F);
2241 }
2242 }
2243
2244 *ke = entry;
2245
2246 return (0);
2247 }
2248
2249
2250 /*
2251 * Map new special codes to old ones.
2252 * Indexed by (new special code) >> 8; add (new special code) & 0xFF.
2253 */
2254 static uchar_t special_new_to_old[] = {
2255 0, /* normal */
2256 OLD_SHIFTKEYS, /* SHIFTKEYS */
2257 OLD_BUCKYBITS, /* BUCKYBITS */
2258 OLD_FUNNY, /* FUNNY */
2259 OLD_FA_UMLAUT, /* FA_CLASS */
2260 OLD_STRING, /* STRING */
2261 OLD_LEFTFUNC, /* FUNCKEYS */
2262 };
2263
2264
2265 /*
2266 * kbtrans_getkey:
2267 * Get individual keystation translation as old-style entry.
2268 */
2269 static int
kbtrans_getkey(struct kbtrans_lower * lower,struct kiockey * key)2270 kbtrans_getkey(struct kbtrans_lower *lower, struct kiockey *key)
2271 {
2272 int strtabindex;
2273 keymap_entry_t *ke;
2274 register keymap_entry_t entry;
2275 struct keyboard *kp;
2276
2277 kp = lower->kbtrans_keyboard;
2278
2279 if (key->kio_station >= kp->k_keymap_size)
2280 return (EINVAL);
2281
2282 if (lower->kbtrans_keyboard == NULL)
2283 return (EINVAL);
2284
2285 switch (key->kio_tablemask) {
2286 case KIOCABORT1:
2287 key->kio_station = kp->k_abort1;
2288 return (0);
2289 case KIOCABORT1A:
2290 key->kio_station = kp->k_abort1a;
2291 return (0);
2292 case KIOCABORT2:
2293 key->kio_station = kp->k_abort2;
2294 return (0);
2295 }
2296
2297 ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2298 key->kio_station);
2299 if (ke == NULL)
2300 return (EINVAL);
2301
2302 entry = *ke;
2303
2304 if (entry & 0xFF00)
2305 key->kio_entry =
2306 special_new_to_old[(ushort_t)(entry & 0xFF00) >> 8]
2307 + (entry & 0x00FF);
2308 else {
2309 if (entry & 0x80)
2310 key->kio_entry = (ushort_t)OLD_ISOCHAR; /* you lose */
2311 else
2312 key->kio_entry = (ushort_t)entry;
2313 }
2314
2315 if (entry >= STRING && entry <= (uchar_t)(STRING + 15)) {
2316 strtabindex = entry - STRING;
2317 bcopy(lower->kbtrans_keystringtab[strtabindex],
2318 key->kio_string, KTAB_STRLEN);
2319 }
2320 return (0);
2321 }
2322
2323
2324 /*
2325 * kbtrans_skey:
2326 * Set individual keystation translation from new-style entry.
2327 */
2328 static int
kbtrans_skey(struct kbtrans_lower * lower,struct kiockeymap * key,cred_t * cr)2329 kbtrans_skey(struct kbtrans_lower *lower, struct kiockeymap *key, cred_t *cr)
2330 {
2331 int strtabindex, i;
2332 keymap_entry_t *ke;
2333 struct keyboard *kp;
2334
2335 kp = lower->kbtrans_keyboard;
2336
2337 if (key->kio_station >= kp->k_keymap_size) {
2338 return (EINVAL);
2339
2340 }
2341
2342 if (lower->kbtrans_keyboard == NULL) {
2343 return (EINVAL);
2344 }
2345
2346 switch (key->kio_tablemask) {
2347 case KIOCABORT1:
2348 case KIOCABORT1A:
2349 case KIOCABORT2:
2350 i = secpolicy_console(cr);
2351 if (i != 0)
2352 return (i);
2353 switch (key->kio_tablemask) {
2354 case KIOCABORT1:
2355 kp->k_abort1 = key->kio_station;
2356 break;
2357 case KIOCABORT1A:
2358 kp->k_abort1a = key->kio_station;
2359 break;
2360 case KIOCABORT2:
2361 kp->k_abort2 = key->kio_station;
2362 break;
2363 }
2364 return (0);
2365 }
2366
2367 ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2368 key->kio_station);
2369 if (ke == NULL)
2370 return (EINVAL);
2371
2372 if (key->kio_entry >= STRING &&
2373 key->kio_entry <= (STRING + 15)) {
2374 strtabindex = key->kio_entry-STRING;
2375 bcopy(key->kio_string,
2376 lower->kbtrans_keystringtab[strtabindex], KTAB_STRLEN);
2377 lower->kbtrans_keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
2378 }
2379
2380 *ke = key->kio_entry;
2381
2382 return (0);
2383 }
2384
2385
2386 /*
2387 * kbtrans_gkey:
2388 * Get individual keystation translation as new-style entry.
2389 */
2390 static int
kbtrans_gkey(struct kbtrans_lower * lower,struct kiockeymap * key)2391 kbtrans_gkey(struct kbtrans_lower *lower, struct kiockeymap *key)
2392 {
2393 int strtabindex;
2394 keymap_entry_t *ke;
2395 struct keyboard *kp;
2396
2397 kp = lower->kbtrans_keyboard;
2398
2399 if (key->kio_station >= kp->k_keymap_size)
2400 return (EINVAL);
2401
2402 if (lower->kbtrans_keyboard == NULL)
2403 return (EINVAL);
2404
2405 switch (key->kio_tablemask) {
2406 case KIOCABORT1:
2407 key->kio_station = kp->k_abort1;
2408 return (0);
2409 case KIOCABORT1A:
2410 key->kio_station = kp->k_abort1a;
2411 return (0);
2412 case KIOCABORT2:
2413 key->kio_station = kp->k_abort2;
2414 return (0);
2415 }
2416
2417 ke = kbtrans_find_entry(lower, (uint_t)key->kio_tablemask,
2418 key->kio_station);
2419 if (ke == NULL)
2420 return (EINVAL);
2421
2422 key->kio_entry = *ke;
2423
2424 if (key->kio_entry >= STRING &&
2425 key->kio_entry <= (STRING + 15)) {
2426 strtabindex = key->kio_entry-STRING;
2427 bcopy(lower->kbtrans_keystringtab[strtabindex],
2428 key->kio_string, KTAB_STRLEN);
2429 }
2430 return (0);
2431 }
2432