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