9000 unix: cleanup 32-bit specific code in fakebop
[unleashed.git] / usr / src / uts / common / io / kbd.c
blob1b58db4c7bfe11ccfa7c1cd7588bb864e1e43fb4
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
27 /* SunOS-4.0 1.60 */
28 /* From: SunOS4.0 sundev/kbd.c */
31 * Keyboard input streams module - handles conversion of up/down codes to
32 * ASCII or event format.
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/sysmacros.h>
37 #include <sys/signal.h>
38 #include <sys/termios.h>
39 #include <sys/termio.h>
40 #include <sys/stream.h>
41 #include <sys/stropts.h>
42 #include <sys/strsun.h>
43 #include <sys/kmem.h>
44 #include <sys/file.h>
45 #include <sys/uio.h>
46 #include <sys/errno.h>
47 #include <sys/time.h>
48 #include <sys/consdev.h>
49 #include <sys/kbd.h>
50 #include <sys/kbio.h>
51 #include <sys/kbdreg.h>
52 #include <sys/vuid_event.h>
53 #include <sys/debug.h>
54 #include <sys/ddi.h>
55 #include <sys/sunddi.h>
56 #include <sys/policy.h>
58 #include <sys/modctl.h>
59 #include <sys/beep.h>
60 #include <sys/int_limits.h>
62 static struct streamtab kbd_info;
64 static struct fmodsw fsw = {
65 "kb",
66 &kbd_info,
67 D_MP | D_MTPERMOD
71 * Module linkage information for the kernel.
74 static struct modlstrmod modlstrmod = {
75 &mod_strmodops, "streams module for keyboard", &fsw
78 static struct modlinkage modlinkage = {
79 MODREV_1, (void *)&modlstrmod, NULL
82 int
83 _init(void)
85 return (mod_install(&modlinkage));
88 int
89 _fini(void)
91 return (mod_remove(&modlinkage));
94 int
95 _info(struct modinfo *modinfop)
97 return (mod_info(&modlinkage, modinfop));
101 * For now these are shared.
102 * These data structures are static (defined in keytables.c) thus
103 * there is no need to perform any locking.
105 extern struct keyboards keytables[];
106 extern char keystringtab[16][KTAB_STRLEN];
107 extern struct compose_sequence_t kb_compose_table[];
108 extern signed char kb_compose_map[];
109 extern struct fltaccent_sequence_t kb_fltaccent_table[];
110 extern uchar_t kb_numlock_table[];
113 * This value corresponds approximately to max 10 fingers
115 static int kbd_downs_size = 15;
117 typedef struct key_event {
118 uchar_t key_station; /* Physical key station associated with event */
119 Firm_event event; /* Event that sent out on down */
120 } Key_event;
121 struct kbddata {
122 queue_t *kbdd_readq;
123 queue_t *kbdd_writeq;
124 mblk_t *kbdd_iocpending; /* "ioctl" awaiting buffer */
125 mblk_t *kbdd_replypending; /* "ioctl" reply awaiting result */
126 int kbdd_flags; /* random flags */
127 bufcall_id_t kbdd_bufcallid; /* bufcall id */
128 timeout_id_t kbdd_rptid; /* timeout id for kbdrpt() */
129 timeout_id_t kbdd_layoutid; /* timeout id for kbdlayout() */
130 int kbdd_iocid; /* ID of "ioctl" being waited for */
131 int kbdd_iocerror; /* error return from "ioctl" */
132 struct keyboardstate kbdd_state;
134 * State of keyboard & keyboard
135 * specific settings, e.g., tables
137 int kbdd_translate; /* Translate keycodes? */
138 int kbdd_translatable; /* Keyboard is translatable? */
139 int kbdd_compat; /* Generating pre-4.1 events? */
140 short kbdd_ascii_addr; /* Vuid_id_addr for ascii events */
141 short kbdd_top_addr; /* Vuid_id_addr for top events */
142 short kbdd_vkey_addr; /* Vuid_id_addr for vkey events */
143 struct key_event *kbdd_downs;
145 * Table of key stations currently down
146 * that have firm events that need
147 * to be matched with up transitions
148 * when kbdd_translate is TR_*EVENT
150 int kbdd_downs_entries; /* # of possible entries in kbdd_downs */
151 uint_t kbdd_downs_bytes; /* # of bytes allocated for kbdd_downs */
152 ushort_t compose_key; /* first compose key */
153 ushort_t fltaccent_entry; /* floating accent keymap entry */
154 char led_state; /* current state of LEDs */
155 unsigned char shiftkey; /* used for the new abort keys */
158 #define KBD_OPEN 0x00000001 /* keyboard is open for business */
159 #define KBD_IOCWAIT 0x00000002 /* "open" waiting for "ioctl" to finish */
161 #define NO_HARD_RESET 0 /* don't do hard reset */
162 #define HARD_RESET 1 /* do hard reset */
166 * Constants setup during the first open of a kbd (so that they can be patched
167 * for debugging purposes).
169 static int kbd_repeatrate;
170 static int kbd_repeatdelay;
172 static int kbd_overflow_cnt; /* Number of times kbd overflowed input q */
173 static int kbd_overflow_msg = 1; /* Whether to print message on q overflow */
175 #ifdef KBD_DEBUG
176 int kbd_debug = 0;
177 int kbd_ra_debug = 0;
178 int kbd_raw_debug = 0;
179 int kbd_rpt_debug = 0;
180 int kbd_input_debug = 0;
181 #endif /* KBD_DEBUG */
183 static int kbdopen(queue_t *, dev_t *, int, int, cred_t *);
184 static int kbdclose(queue_t *, int, cred_t *);
185 static void kbdwput(queue_t *, mblk_t *);
186 static void kbdrput(queue_t *, mblk_t *);
188 static struct module_info kbdmiinfo = {
190 "kb",
192 INFPSZ,
193 2048,
197 static struct qinit kbdrinit = {
198 (int (*)())kbdrput,
199 (int (*)())NULL,
200 kbdopen,
201 kbdclose,
202 (int (*)())NULL,
203 &kbdmiinfo
206 static struct module_info kbdmoinfo = {
208 "kb",
210 INFPSZ,
211 2048,
215 static struct qinit kbdwinit = {
216 (int (*)())kbdwput,
217 (int (*)())NULL,
218 kbdopen,
219 kbdclose,
220 (int (*)())NULL,
221 &kbdmoinfo
224 static struct streamtab kbd_info = {
225 &kbdrinit,
226 &kbdwinit,
227 NULL,
228 NULL,
231 static void kbdreioctl(void *);
232 static void kbdioctl(queue_t *, mblk_t *);
233 static void kbdflush(struct kbddata *);
234 static void kbduse(struct kbddata *, unsigned);
235 static void kbdsetled(struct kbddata *);
236 static void kbd_beep_off(void *arg);
237 static void kbd_beep_on(void *arg);
238 static void kbdcmd(queue_t *, char);
239 static void kbdreset(struct kbddata *, uint_t);
240 static int kbdsetkey(struct kbddata *, struct kiockey *, cred_t *);
241 static int kbdgetkey(struct kbddata *, struct kiockey *);
242 static int kbdskey(struct kbddata *, struct kiockeymap *, cred_t *);
243 static int kbdgkey(struct kbddata *, struct kiockeymap *);
244 static void kbdlayouttimeout(void *);
245 static void kbdinput(struct kbddata *, unsigned);
246 static void kbdid(struct kbddata *, int);
247 static struct keymap *settable(struct kbddata *, uint_t);
248 static void kbdrpt(void *);
249 static void kbdcancelrpt(struct kbddata *);
250 static void kbdtranslate(struct kbddata *, unsigned, queue_t *);
251 static int kbd_do_compose(ushort_t, ushort_t, ushort_t *);
252 static void kbd_send_esc_event(char, struct kbddata *);
253 char *strsetwithdecimal(char *, uint_t, uint_t);
254 static void kbdkeypressed(struct kbddata *, uchar_t, Firm_event *,
255 ushort_t);
256 static void kbdqueuepress(struct kbddata *, uchar_t, Firm_event *);
257 static void kbdkeyreleased(struct kbddata *, uchar_t);
258 static void kbdreleaseall(struct kbddata *);
259 static void kbdputcode(uint_t, queue_t *);
260 static void kbdputbuf(char *, queue_t *);
261 static void kbdqueueevent(struct kbddata *, Firm_event *);
264 * Dummy qbufcall callback routine used by open and close.
265 * The framework will wake up qwait_sig when we return from
266 * this routine (as part of leaving the perimeters.)
267 * (The framework enters the perimeters before calling the qbufcall() callback
268 * and leaves the perimeters after the callback routine has executed. The
269 * framework performs an implicit wakeup of any thread in qwait/qwait_sig
270 * when it leaves the perimeter. See qwait(9E).)
272 /* ARGSUSED */
273 static void dummy_callback(void *arg)
278 * Open a keyboard.
279 * Ttyopen sets line characteristics
281 /* ARGSUSED */
282 static int
283 kbdopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
285 register int error;
286 register struct kbddata *kbdd;
287 mblk_t *mp;
288 mblk_t *datap;
289 register struct iocblk *iocb;
290 register struct termios *cb;
292 /* Set these up only once so that they could be changed from adb */
293 if (!kbd_repeatrate) {
294 kbd_repeatrate = (hz+29)/30;
295 kbd_repeatdelay = hz/2;
298 if (q->q_ptr != NULL)
299 return (0); /* already attached */
302 * Only allow open requests to succeed for privileged users. This
303 * necessary to prevent users from pushing the "kb" module again
304 * on the stream associated with /dev/kbd.
306 if (secpolicy_console(crp) != 0) {
307 return (EPERM);
311 switch (sflag) {
313 case MODOPEN:
314 break;
316 case CLONEOPEN:
317 return (EINVAL); /* No Bozos! */
320 /* allocate keyboard */
322 kbdd = kmem_zalloc(sizeof (struct kbddata), KM_SLEEP);
326 * Set up queue pointers, so that the "put" procedure will accept
327 * the reply to the "ioctl" message we send down.
329 q->q_ptr = kbdd;
330 WR(q)->q_ptr = kbdd;
332 qprocson(q);
335 * Setup tty modes.
337 while ((mp = mkiocb(TCSETSF)) == NULL) {
338 timeout_id_t id = qbufcall(q, sizeof (struct iocblk), BPRI_HI,
339 dummy_callback, NULL);
340 if (!qwait_sig(q)) {
341 qunbufcall(q, id);
342 kmem_free(kbdd, sizeof (struct kbddata));
343 qprocsoff(q);
345 return (EINTR);
348 while ((datap = allocb(sizeof (struct termios), BPRI_HI)) ==
349 NULL) {
350 timeout_id_t id = qbufcall(q, sizeof (struct termios), BPRI_HI,
351 dummy_callback, NULL);
352 if (!qwait_sig(q)) {
353 qunbufcall(q, id);
354 freemsg(mp);
355 kmem_free(kbdd, sizeof (struct kbddata));
356 qprocsoff(q);
358 return (EINTR);
362 iocb = (struct iocblk *)mp->b_rptr;
363 iocb->ioc_count = sizeof (struct termios);
365 cb = (struct termios *)datap->b_rptr;
366 cb->c_iflag = 0;
367 cb->c_oflag = 0;
368 cb->c_cflag = CREAD|CS8|B1200;
369 cb->c_lflag = 0;
370 bzero(cb->c_cc, NCCS);
371 datap->b_wptr += sizeof (struct termios);
372 mp->b_cont = datap;
373 kbdd->kbdd_flags |= KBD_IOCWAIT; /* indicate that we're */
374 kbdd->kbdd_iocid = iocb->ioc_id; /* waiting for this response */
375 putnext(WR(q), mp);
378 * Now wait for it. Let our read queue put routine wake us up
379 * when it arrives.
381 while (kbdd->kbdd_flags & KBD_IOCWAIT) {
382 if (!qwait_sig(q)) {
383 error = EINTR;
384 goto error;
387 if ((error = kbdd->kbdd_iocerror) != 0)
388 goto error;
391 * Set up private data.
393 kbdd->kbdd_readq = q;
394 kbdd->kbdd_writeq = WR(q);
395 kbdd->kbdd_iocpending = NULL;
396 kbdd->kbdd_translatable = TR_CAN;
397 kbdd->kbdd_translate = TR_ASCII;
398 kbdd->kbdd_compat = 1;
399 kbdd->kbdd_ascii_addr = ASCII_FIRST;
400 kbdd->kbdd_top_addr = TOP_FIRST;
401 kbdd->kbdd_vkey_addr = VKEY_FIRST;
402 /* Allocate dynamic memory for downs table */
403 kbdd->kbdd_downs_entries = kbd_downs_size;
404 kbdd->kbdd_downs_bytes = kbd_downs_size * sizeof (Key_event);
405 kbdd->kbdd_downs = kmem_alloc(kbdd->kbdd_downs_bytes, KM_SLEEP);
406 kbdd->kbdd_flags = KBD_OPEN;
407 kbdd->led_state = 0;
410 * Reset kbd.
412 kbdreset(kbdd, HARD_RESET);
414 (void) beep_init((void *)WR(q), kbd_beep_on, kbd_beep_off, NULL);
416 return (0);
418 error:
419 qprocsoff(q);
420 kmem_free(kbdd, sizeof (struct kbddata));
421 return (error);
425 * Close a keyboard.
427 /* ARGSUSED1 */
428 static int
429 kbdclose(register queue_t *q, int flag, cred_t *crp)
431 register struct kbddata *kbdd = (struct kbddata *)q->q_ptr;
432 register mblk_t *mp;
434 qprocsoff(q);
435 (void) beep_fini();
437 * Since we're about to destroy our private data, turn off
438 * our open flag first, so we don't accept any more input
439 * and try to use that data.
441 kbdd->kbdd_flags = 0;
443 if ((mp = kbdd->kbdd_replypending) != NULL) {
445 * There was a KIOCLAYOUT pending; presumably, it timed out.
446 * Throw the reply away.
448 kbdd->kbdd_replypending = NULL;
449 freemsg(mp);
452 /* clear all timeouts */
453 if (kbdd->kbdd_bufcallid)
454 qunbufcall(q, kbdd->kbdd_bufcallid);
455 if (kbdd->kbdd_rptid)
456 (void) quntimeout(q, kbdd->kbdd_rptid);
457 if (kbdd->kbdd_layoutid)
458 (void) quntimeout(q, kbdd->kbdd_layoutid);
459 kmem_free(kbdd->kbdd_downs, kbdd->kbdd_downs_bytes);
460 kmem_free(kbdd, sizeof (struct kbddata));
461 return (0);
465 * Line discipline output queue put procedure: handles M_IOCTL
466 * messages.
468 static void
469 kbdwput(register queue_t *q, register mblk_t *mp)
472 * Process M_FLUSH, and some M_IOCTL, messages here; pass
473 * everything else down.
475 switch (mp->b_datap->db_type) {
477 case M_FLUSH:
478 if (*mp->b_rptr & FLUSHW)
479 flushq(q, FLUSHDATA);
480 if (*mp->b_rptr & FLUSHR)
481 flushq(RD(q), FLUSHDATA);
483 default:
484 putnext(q, mp); /* pass it down the line */
485 break;
487 case M_IOCTL:
488 kbdioctl(q, mp);
489 break;
494 static void
495 kbdreioctl(void *kbdd_addr)
497 struct kbddata *kbdd = kbdd_addr;
498 queue_t *q;
499 mblk_t *mp;
501 kbdd->kbdd_bufcallid = 0;
502 q = kbdd->kbdd_writeq;
503 if ((mp = kbdd->kbdd_iocpending) != NULL) {
504 kbdd->kbdd_iocpending = NULL; /* not pending any more */
505 kbdioctl(q, mp);
509 static void
510 kbdioctl(register queue_t *q, register mblk_t *mp)
512 register struct kbddata *kbdd = (struct kbddata *)q->q_ptr;
513 register struct iocblk *iocp;
514 register short new_translate;
515 register Vuid_addr_probe *addr_probe;
516 register short *addr_ptr;
517 mblk_t *datap;
518 size_t ioctlrespsize;
519 int err = 0;
520 int tmp;
521 int cycles;
522 int frequency;
523 int msecs;
525 iocp = (struct iocblk *)mp->b_rptr;
527 switch (iocp->ioc_cmd) {
529 case VUIDSFORMAT:
530 err = miocpullup(mp, sizeof (int));
531 if (err != 0)
532 break;
534 new_translate = (*(int *)mp->b_cont->b_rptr == VUID_NATIVE) ?
535 TR_ASCII : TR_EVENT;
536 if (new_translate == kbdd->kbdd_translate)
537 break;
538 kbdd->kbdd_translate = new_translate;
539 goto output_format_change;
541 case KIOCTRANS:
542 err = miocpullup(mp, sizeof (int));
543 if (err != 0)
544 break;
546 new_translate = *(int *)mp->b_cont->b_rptr;
547 if (new_translate == kbdd->kbdd_translate)
548 break;
549 kbdd->kbdd_translate = new_translate;
550 goto output_format_change;
552 case KIOCCMD:
553 err = miocpullup(mp, sizeof (int));
554 if (err != 0)
555 break;
557 tmp = (char)(*(int *)mp->b_cont->b_rptr);
558 if (tmp == KBD_CMD_BELL)
559 (void) beeper_on(BEEP_TYPE4);
560 else if (tmp == KBD_CMD_NOBELL)
561 (void) beeper_off();
562 else
563 kbdcmd(q, tmp);
564 break;
566 case KIOCMKTONE:
567 if (iocp->ioc_count != TRANSPARENT) {
569 * We don't support non-transparent ioctls,
570 * i.e. I_STR ioctls
572 err = EINVAL;
573 break;
575 tmp = (int)(*(intptr_t *)mp->b_cont->b_rptr);
576 cycles = tmp & 0xffff;
577 msecs = (tmp >> 16) & 0xffff;
579 if (cycles == 0)
580 frequency = UINT16_MAX;
581 else if (cycles == UINT16_MAX)
582 frequency = 0;
583 else {
584 frequency = (PIT_HZ + cycles / 2) / cycles;
585 if (frequency > UINT16_MAX)
586 frequency = UINT16_MAX;
589 err = beep_mktone(frequency, msecs);
590 break;
592 case KIOCSLED:
593 err = miocpullup(mp, sizeof (uchar_t));
594 if (err != 0)
595 break;
597 kbdd->led_state = *(uchar_t *)mp->b_cont->b_rptr;
598 kbdsetled(kbdd);
599 break;
601 case KIOCGLED:
602 if ((datap = allocb(sizeof (uchar_t), BPRI_HI)) == NULL) {
603 ioctlrespsize = sizeof (int);
604 goto allocfailure;
606 *(uchar_t *)datap->b_wptr = kbdd->led_state;
607 datap->b_wptr += sizeof (uchar_t);
608 if (mp->b_cont) /* free msg to prevent memory leak */
609 freemsg(mp->b_cont);
610 mp->b_cont = datap;
611 iocp->ioc_count = sizeof (uchar_t);
612 break;
614 case VUIDGFORMAT:
615 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
616 ioctlrespsize = sizeof (int);
617 goto allocfailure;
619 *(int *)datap->b_wptr =
620 (kbdd->kbdd_translate == TR_EVENT ||
621 kbdd->kbdd_translate == TR_UNTRANS_EVENT) ?
622 VUID_FIRM_EVENT: VUID_NATIVE;
623 datap->b_wptr += sizeof (int);
624 if (mp->b_cont) /* free msg to prevent memory leak */
625 freemsg(mp->b_cont);
626 mp->b_cont = datap;
627 iocp->ioc_count = sizeof (int);
628 break;
630 case KIOCGTRANS:
631 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
632 ioctlrespsize = sizeof (int);
633 goto allocfailure;
635 *(int *)datap->b_wptr = kbdd->kbdd_translate;
636 datap->b_wptr += sizeof (int);
637 if (mp->b_cont) /* free msg to prevent memory leak */
638 freemsg(mp->b_cont);
639 mp->b_cont = datap;
640 iocp->ioc_count = sizeof (int);
641 break;
643 case VUIDSADDR:
644 err = miocpullup(mp, sizeof (Vuid_addr_probe));
645 if (err != 0)
646 break;
648 addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
649 switch (addr_probe->base) {
651 case ASCII_FIRST:
652 addr_ptr = &kbdd->kbdd_ascii_addr;
653 break;
655 case TOP_FIRST:
656 addr_ptr = &kbdd->kbdd_top_addr;
657 break;
659 case VKEY_FIRST:
660 addr_ptr = &kbdd->kbdd_vkey_addr;
661 break;
663 default:
664 err = ENODEV;
666 if ((err == 0) && (*addr_ptr != addr_probe->data.next)) {
667 *addr_ptr = addr_probe->data.next;
668 goto output_format_change;
670 break;
672 case VUIDGADDR:
673 err = miocpullup(mp, sizeof (Vuid_addr_probe));
674 if (err != 0)
675 break;
677 addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
678 switch (addr_probe->base) {
680 case ASCII_FIRST:
681 addr_probe->data.current = kbdd->kbdd_ascii_addr;
682 break;
684 case TOP_FIRST:
685 addr_probe->data.current = kbdd->kbdd_top_addr;
686 break;
688 case VKEY_FIRST:
689 addr_probe->data.current = kbdd->kbdd_vkey_addr;
690 break;
692 default:
693 err = ENODEV;
695 break;
697 case KIOCTRANSABLE:
698 err = miocpullup(mp, sizeof (int));
699 if (err != 0)
700 break;
702 if (kbdd->kbdd_translatable != *(int *)mp->b_cont->b_rptr) {
703 kbdd->kbdd_translatable = *(int *)mp->b_cont->b_rptr;
704 kbdreset(kbdd, HARD_RESET);
705 goto output_format_change;
707 break;
709 case KIOCGTRANSABLE:
710 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
711 ioctlrespsize = sizeof (int);
712 goto allocfailure;
714 *(int *)datap->b_wptr = kbdd->kbdd_translatable;
715 datap->b_wptr += sizeof (int);
716 if (mp->b_cont) /* free msg to prevent memory leak */
717 freemsg(mp->b_cont);
718 mp->b_cont = datap;
719 iocp->ioc_count = sizeof (int);
720 break;
722 case KIOCSCOMPAT:
723 err = miocpullup(mp, sizeof (int));
724 if (err != 0)
725 break;
727 kbdd->kbdd_compat = *(int *)mp->b_cont->b_rptr;
728 break;
730 case KIOCGCOMPAT:
731 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
732 ioctlrespsize = sizeof (int);
733 goto allocfailure;
735 *(int *)datap->b_wptr = kbdd->kbdd_compat;
736 datap->b_wptr += sizeof (int);
737 if (mp->b_cont) /* free msg to prevent memory leak */
738 freemsg(mp->b_cont);
739 mp->b_cont = datap;
740 iocp->ioc_count = sizeof (int);
741 break;
743 case KIOCSETKEY:
744 err = miocpullup(mp, sizeof (struct kiockey));
745 if (err != 0)
746 break;
748 err = kbdsetkey(kbdd, (struct kiockey *)mp->b_cont->b_rptr,
749 iocp->ioc_cr);
751 * Since this only affects any subsequent key presses,
752 * don't goto output_format_change. One might want to
753 * toggle the keytable entries dynamically.
755 break;
757 case KIOCGETKEY:
758 err = miocpullup(mp, sizeof (struct kiockey));
759 if (err != 0)
760 break;
762 err = kbdgetkey(kbdd, (struct kiockey *)mp->b_cont->b_rptr);
763 break;
765 case KIOCSKEY:
766 err = miocpullup(mp, sizeof (struct kiockeymap));
767 if (err != 0)
768 break;
770 err = kbdskey(kbdd, (struct kiockeymap *)mp->b_cont->b_rptr,
771 iocp->ioc_cr);
773 * Since this only affects any subsequent key presses,
774 * don't goto output_format_change. One might want to
775 * toggle the keytable entries dynamically.
777 break;
779 case KIOCGKEY:
780 err = miocpullup(mp, sizeof (struct kiockeymap));
781 if (err != 0)
782 break;
784 err = kbdgkey(kbdd, (struct kiockeymap *)mp->b_cont->b_rptr);
785 break;
787 case KIOCSDIRECT:
788 goto output_format_change;
790 case KIOCGDIRECT:
791 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
792 ioctlrespsize = sizeof (int);
793 goto allocfailure;
795 *(int *)datap->b_wptr = 1; /* always direct */
796 datap->b_wptr += sizeof (int);
797 if (mp->b_cont) /* free msg to prevent memory leak */
798 freemsg(mp->b_cont);
799 mp->b_cont = datap;
800 iocp->ioc_count = sizeof (int);
801 break;
803 case KIOCTYPE:
804 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
805 ioctlrespsize = sizeof (int);
806 goto allocfailure;
808 *(int *)datap->b_wptr = kbdd->kbdd_state.k_id;
809 datap->b_wptr += sizeof (int);
810 if (mp->b_cont) /* free msg to prevent memory leak */
811 freemsg(mp->b_cont);
812 mp->b_cont = datap;
813 iocp->ioc_count = sizeof (int);
814 break;
816 case KIOCLAYOUT:
817 if ((datap = kbdd->kbdd_replypending) != NULL) {
819 * There was an earlier KIOCLAYOUT pending; presumably,
820 * it timed out. Throw the reply away.
822 kbdd->kbdd_replypending = NULL;
823 freemsg(datap);
826 if (kbdd->kbdd_state.k_id == KB_SUN4 ||
827 kbdd->kbdd_state.k_id == KB_PC) {
828 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
829 ioctlrespsize = sizeof (int);
830 goto allocfailure;
832 iocp->ioc_rval = 0;
833 iocp->ioc_error = 0; /* brain rot */
834 iocp->ioc_count = sizeof (int);
835 if (mp->b_cont) /* free msg to prevent memory leak */
836 freemsg(mp->b_cont);
837 mp->b_cont = datap;
838 mp->b_datap->db_type = M_IOCACK;
839 kbdd->kbdd_replypending = mp;
840 kbdcmd(q, (char)KBD_CMD_GETLAYOUT);
841 if (kbdd->kbdd_layoutid)
842 (void) quntimeout(q, kbdd->kbdd_layoutid);
843 kbdd->kbdd_layoutid = qtimeout(q, kbdlayouttimeout,
844 kbdd, hz / 5);
845 return; /* wait for reply from keyboard */
846 } else {
848 * Not a Type 4 keyboard; return an immediate error.
850 err = EINVAL;
851 break;
854 case KIOCGRPTDELAY:
856 * Report the autorepeat delay, unit in millisecond
858 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
859 ioctlrespsize = sizeof (int);
860 goto allocfailure;
862 *(int *)datap->b_wptr = TICK_TO_MSEC(kbd_repeatdelay);
863 datap->b_wptr += sizeof (int);
865 /* free msg to prevent memory leak */
866 if (mp->b_cont != NULL)
867 freemsg(mp->b_cont);
868 mp->b_cont = datap;
869 iocp->ioc_count = sizeof (int);
870 break;
872 case KIOCSRPTDELAY:
874 * Set the autorepeat delay
876 err = miocpullup(mp, sizeof (int));
878 if (err != 0)
879 break;
881 /* validate the input */
882 if (*(int *)mp->b_cont->b_rptr < KIOCRPTDELAY_MIN) {
883 err = EINVAL;
884 break;
886 kbd_repeatdelay = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
887 if (kbd_repeatdelay <= 0)
888 kbd_repeatdelay = 1;
889 break;
891 case KIOCGRPTRATE:
893 * Report the autorepeat rate
895 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
896 ioctlrespsize = sizeof (int);
897 goto allocfailure;
899 *(int *)datap->b_wptr = TICK_TO_MSEC(kbd_repeatrate);
900 datap->b_wptr += sizeof (int);
902 /* free msg to prevent memory leak */
903 if (mp->b_cont != NULL)
904 freemsg(mp->b_cont);
905 mp->b_cont = datap;
906 iocp->ioc_count = sizeof (int);
907 break;
909 case KIOCSRPTRATE:
911 * Set the autorepeat rate
913 err = miocpullup(mp, sizeof (int));
915 if (err != 0)
916 break;
918 /* validate the input */
919 if (*(int *)mp->b_cont->b_rptr < KIOCRPTRATE_MIN) {
920 err = EINVAL;
921 break;
923 kbd_repeatrate = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
924 if (kbd_repeatrate <= 0)
925 kbd_repeatrate = 1;
926 break;
928 default:
929 putnext(q, mp); /* pass it down the line */
930 return;
932 goto done;
934 output_format_change:
935 kbdflush(kbdd);
937 done:
938 if (err != 0) {
939 iocp->ioc_rval = 0;
940 iocp->ioc_error = err;
941 mp->b_datap->db_type = M_IOCNAK;
942 } else {
943 iocp->ioc_rval = 0;
944 iocp->ioc_error = 0; /* brain rot */
945 mp->b_datap->db_type = M_IOCACK;
947 qreply(q, mp);
948 return;
950 allocfailure:
952 * We needed to allocate something to handle this "ioctl", but
953 * couldn't; save this "ioctl" and arrange to get called back when
954 * it's more likely that we can get what we need.
955 * If there's already one being saved, throw it out, since it
956 * must have timed out.
958 if (kbdd->kbdd_iocpending != NULL)
959 freemsg(kbdd->kbdd_iocpending);
960 kbdd->kbdd_iocpending = mp;
961 if (kbdd->kbdd_bufcallid)
962 qunbufcall(q, kbdd->kbdd_bufcallid);
963 kbdd->kbdd_bufcallid = qbufcall(q, ioctlrespsize, BPRI_HI,
964 kbdreioctl, kbdd);
967 static void
968 kbdflush(register struct kbddata *kbdd)
970 register queue_t *q;
972 /* Flush pending data already sent upstream */
973 if ((q = kbdd->kbdd_readq) != NULL && q->q_next != NULL)
974 (void) putnextctl1(q, M_FLUSH, FLUSHR);
975 /* Flush pending ups */
976 bzero(kbdd->kbdd_downs, kbdd->kbdd_downs_bytes);
977 kbdcancelrpt(kbdd);
981 * Pass keycode upstream, either translated or untranslated.
983 static void
984 kbduse(register struct kbddata *kbdd, unsigned keycode)
986 register queue_t *readq;
988 #ifdef KBD_DEBUG
989 if (kbd_input_debug) printf("KBD USE key=%d\n", keycode);
990 #endif
992 if ((readq = kbdd->kbdd_readq) == NULL)
993 return;
994 if (!kbdd->kbdd_translatable ||
995 kbdd->kbdd_translate == TR_NONE)
996 kbdputcode(keycode, readq);
997 else
998 kbdtranslate(kbdd, keycode, readq);
1001 static void
1002 kbd_beep_on(void *arg)
1004 kbdcmd((queue_t *)arg, KBD_CMD_BELL);
1008 static void
1009 kbd_beep_off(void *arg)
1011 kbdcmd((queue_t *)arg, KBD_CMD_NOBELL);
1016 * kbdclick is used to remember the current click value of the
1017 * Sun-3 keyboard. This brain damaged keyboard will reset the
1018 * clicking to the "default" value after a reset command and
1019 * there is no way to read out the current click value. We
1020 * cannot send a click command immediately after the reset
1021 * command or the keyboard gets screwed up. So we wait until
1022 * we get the ID byte before we send back the click command.
1023 * Unfortunately, this means that there is a small window
1024 * where the keyboard can click when it really shouldn't be.
1025 * A value of -1 means that kbdclick has not been initialized yet.
1027 static int kbdclick = -1;
1030 * Send command byte to keyboard, if you can.
1032 static void
1033 kbdcmd(register queue_t *q, char cmd)
1035 register mblk_t *bp;
1037 if (canput(q)) {
1038 if ((bp = allocb(1, BPRI_MED)) == NULL)
1039 cmn_err(CE_WARN,
1040 "kbdcmd: Can't allocate block for command");
1041 else {
1042 *bp->b_wptr++ = cmd;
1043 putnext(q, bp);
1044 if (cmd == KBD_CMD_NOCLICK)
1045 kbdclick = 0;
1046 else if (cmd == KBD_CMD_CLICK)
1047 kbdclick = 1;
1053 * Update the keyboard LEDs to match the current keyboard state.
1054 * Do this only on Type 4 keyboards; other keyboards don't support the
1055 * KBD_CMD_SETLED command (nor, for that matter, the appropriate LEDs).
1057 static void
1058 kbdsetled(register struct kbddata *kbdd)
1060 if (kbdd->kbdd_state.k_id == KB_SUN4 ||
1061 kbdd->kbdd_state.k_id == KB_PC) {
1062 kbdcmd(kbdd->kbdd_writeq, KBD_CMD_SETLED);
1063 kbdcmd(kbdd->kbdd_writeq, kbdd->led_state);
1068 * Reset the keyboard
1070 static void
1071 kbdreset(register struct kbddata *kbdd, uint_t hard_reset)
1073 register struct keyboardstate *k;
1075 k = &kbdd->kbdd_state;
1076 if (kbdd->kbdd_translatable) {
1077 k->k_idstate = KID_NONE;
1078 k->k_id = -1;
1079 k->k_state = NORMAL;
1080 if (hard_reset)
1081 kbdcmd(kbdd->kbdd_writeq, KBD_CMD_RESET);
1082 } else {
1083 bzero(k, sizeof (struct keyboardstate));
1084 k->k_id = KB_ASCII;
1085 k->k_idstate = KID_OK;
1090 * Old special codes.
1092 #define OLD_SHIFTKEYS 0x80
1093 #define OLD_BUCKYBITS 0x90
1094 #define OLD_FUNNY 0xA0
1095 #define OLD_FA_UMLAUT 0xA9
1096 #define OLD_FA_CFLEX 0xAA
1097 #define OLD_FA_TILDE 0xAB
1098 #define OLD_FA_CEDILLA 0xAC
1099 #define OLD_FA_ACUTE 0xAD
1100 #define OLD_FA_GRAVE 0xAE
1101 #define OLD_ISOCHAR 0xAF
1102 #define OLD_STRING 0xB0
1103 #define OLD_LEFTFUNC 0xC0
1104 #define OLD_RIGHTFUNC 0xD0
1105 #define OLD_TOPFUNC 0xE0
1106 #define OLD_BOTTOMFUNC 0xF0
1109 * Map old special codes to new ones.
1110 * Indexed by ((old special code) >> 4) & 0x07; add (old special code) & 0x0F.
1112 static ushort_t special_old_to_new[] = {
1113 SHIFTKEYS,
1114 BUCKYBITS,
1115 FUNNY,
1116 STRING,
1117 LEFTFUNC,
1118 RIGHTFUNC,
1119 TOPFUNC,
1120 BOTTOMFUNC,
1124 * Set individual keystation translation from old-style entry.
1125 * TODO: Have each keyboard own own translation tables.
1127 static int
1128 kbdsetkey(register struct kbddata *kbdd, struct kiockey *key, cred_t *cr)
1130 int strtabindex, i;
1131 struct keymap *km;
1132 register int tablemask;
1133 register ushort_t entry;
1135 if (key->kio_station >= KEYMAP_SIZE)
1136 return (EINVAL);
1137 if (kbdd->kbdd_state.k_curkeyboard == NULL)
1138 return (EINVAL);
1139 tablemask = key->kio_tablemask;
1140 if (tablemask == KIOCABORT1) {
1141 if (secpolicy_console(cr) != 0)
1142 return (EPERM);
1143 kbdd->kbdd_state.k_curkeyboard->k_abort1 = key->kio_station;
1144 return (0);
1146 if (tablemask == KIOCABORT2) {
1147 if (secpolicy_console(cr) != 0)
1148 return (EPERM);
1149 kbdd->kbdd_state.k_curkeyboard->k_abort2 = key->kio_station;
1150 return (0);
1152 if ((tablemask & ALTGRAPHMASK) ||
1153 (km = settable(kbdd, (uint_t)tablemask)) == NULL)
1154 return (EINVAL);
1155 if (key->kio_entry >= (uchar_t)OLD_STRING &&
1156 key->kio_entry <= (uchar_t)(OLD_STRING + 15)) {
1157 strtabindex = key->kio_entry - OLD_STRING;
1158 for (i = 0; i < KTAB_STRLEN; i++)
1159 keystringtab[strtabindex][i] = key->kio_string[i];
1160 keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
1162 entry = key->kio_entry;
1164 * There's nothing we need do with OLD_ISOCHAR.
1166 if (entry != OLD_ISOCHAR) {
1167 if (entry & 0x80) {
1168 if (entry >= OLD_FA_UMLAUT && entry <= OLD_FA_GRAVE)
1169 entry = FA_CLASS + (entry & 0x0F) - 9;
1170 else
1171 entry =
1172 special_old_to_new[entry >> 4 & 0x07]
1173 + (entry & 0x0F);
1176 km->keymap[key->kio_station] = entry;
1177 return (0);
1181 * Map new special codes to old ones.
1182 * Indexed by (new special code) >> 8; add (new special code) & 0xFF.
1184 static uchar_t special_new_to_old[] = {
1185 0, /* normal */
1186 OLD_SHIFTKEYS, /* SHIFTKEYS */
1187 OLD_BUCKYBITS, /* BUCKYBITS */
1188 OLD_FUNNY, /* FUNNY */
1189 OLD_FA_UMLAUT, /* FA_CLASS */
1190 OLD_STRING, /* STRING */
1191 OLD_LEFTFUNC, /* FUNCKEYS */
1195 * Get individual keystation translation as old-style entry.
1197 static int
1198 kbdgetkey(register struct kbddata *kbdd, struct kiockey *key)
1200 int strtabindex, i;
1201 struct keymap *km;
1202 register ushort_t entry;
1204 if (key->kio_station >= KEYMAP_SIZE)
1205 return (EINVAL);
1206 if (kbdd->kbdd_state.k_curkeyboard == NULL)
1207 return (EINVAL);
1208 if (key->kio_tablemask == KIOCABORT1) {
1209 key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort1;
1210 return (0);
1212 if (key->kio_tablemask == KIOCABORT2) {
1213 key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort2;
1214 return (0);
1216 if ((km = settable(kbdd, (uint_t)key->kio_tablemask)) == NULL)
1217 return (EINVAL);
1218 entry = km->keymap[key->kio_station];
1219 if (entry & 0xFF00)
1220 key->kio_entry =
1221 special_new_to_old[(ushort_t)(entry & 0xFF00) >> 8]
1222 + (entry & 0x00FF);
1223 else {
1224 if (entry & 0x80)
1225 key->kio_entry = (ushort_t)OLD_ISOCHAR; /* you lose */
1226 else
1227 key->kio_entry = (ushort_t)entry;
1229 if (entry >= STRING && entry <= (uchar_t)(STRING + 15)) {
1230 strtabindex = entry - STRING;
1231 for (i = 0; i < KTAB_STRLEN; i++)
1232 key->kio_string[i] = keystringtab[strtabindex][i];
1234 return (0);
1238 * Set individual keystation translation from new-style entry.
1239 * TODO: Have each keyboard own own translation tables.
1241 static int
1242 kbdskey(register struct kbddata *kbdd, struct kiockeymap *key, cred_t *cr)
1244 int strtabindex, i;
1245 struct keymap *km;
1247 if (key->kio_station >= KEYMAP_SIZE)
1248 return (EINVAL);
1249 if (kbdd->kbdd_state.k_curkeyboard == NULL)
1250 return (EINVAL);
1251 if (key->kio_tablemask == KIOCABORT1) {
1252 if (secpolicy_console(cr) != 0)
1253 return (EPERM);
1254 kbdd->kbdd_state.k_curkeyboard->k_abort1 = key->kio_station;
1255 return (0);
1257 if (key->kio_tablemask == KIOCABORT2) {
1258 if (secpolicy_console(cr) != 0)
1259 return (EPERM);
1260 kbdd->kbdd_state.k_curkeyboard->k_abort2 = key->kio_station;
1261 return (0);
1263 if ((km = settable(kbdd, (uint_t)key->kio_tablemask)) == NULL)
1264 return (EINVAL);
1265 if (key->kio_entry >= STRING &&
1266 key->kio_entry <= (ushort_t)(STRING + 15)) {
1267 strtabindex = key->kio_entry-STRING;
1268 for (i = 0; i < KTAB_STRLEN; i++)
1269 keystringtab[strtabindex][i] = key->kio_string[i];
1270 keystringtab[strtabindex][KTAB_STRLEN-1] = '\0';
1272 km->keymap[key->kio_station] = key->kio_entry;
1273 return (0);
1277 * Get individual keystation translation as new-style entry.
1279 static int
1280 kbdgkey(register struct kbddata *kbdd, struct kiockeymap *key)
1282 int strtabindex, i;
1283 struct keymap *km;
1285 if (key->kio_station >= KEYMAP_SIZE)
1286 return (EINVAL);
1287 if (kbdd->kbdd_state.k_curkeyboard == NULL)
1288 return (EINVAL);
1289 if (key->kio_tablemask == KIOCABORT1) {
1290 key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort1;
1291 return (0);
1293 if (key->kio_tablemask == KIOCABORT2) {
1294 key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort2;
1295 return (0);
1297 if ((km = settable(kbdd, (uint_t)key->kio_tablemask)) == NULL)
1298 return (EINVAL);
1299 key->kio_entry = km->keymap[key->kio_station];
1300 if (key->kio_entry >= STRING &&
1301 key->kio_entry <= (ushort_t)(STRING + 15)) {
1302 strtabindex = key->kio_entry-STRING;
1303 for (i = 0; i < KTAB_STRLEN; i++)
1304 key->kio_string[i] = keystringtab[strtabindex][i];
1306 return (0);
1309 static void
1310 kbdlayouttimeout(void *arg)
1312 struct kbddata *kbdd = arg;
1313 mblk_t *mp;
1315 kbdd->kbdd_layoutid = 0;
1318 * Timed out waiting for reply to "get keyboard layout" command.
1319 * Return an ETIME error.
1321 if ((mp = kbdd->kbdd_replypending) != NULL) {
1322 kbdd->kbdd_replypending = NULL;
1323 mp->b_datap->db_type = M_IOCNAK;
1324 ((struct iocblk *)mp->b_rptr)->ioc_error = ETIME;
1325 putnext(kbdd->kbdd_readq, mp);
1330 * Put procedure for input from driver end of stream (read queue).
1332 static void
1333 kbdrput(register queue_t *q, register mblk_t *mp)
1335 struct kbddata *kbdd = (struct kbddata *)q->q_ptr;
1336 register mblk_t *bp;
1337 register uchar_t *readp;
1338 struct iocblk *iocp;
1340 if (kbdd == 0) {
1341 freemsg(mp); /* nobody's listening */
1342 return;
1345 switch (mp->b_datap->db_type) {
1347 case M_FLUSH:
1348 if (*mp->b_rptr & FLUSHW)
1349 flushq(WR(q), FLUSHDATA);
1350 if (*mp->b_rptr & FLUSHR)
1351 flushq(q, FLUSHDATA);
1353 default:
1354 putnext(q, mp);
1355 return;
1357 case M_BREAK:
1359 * Will get M_BREAK only if this is not the system
1360 * keyboard, otherwise serial port will eat break
1361 * and call kmdb/OBP, without passing anything up.
1363 freemsg(mp);
1364 return;
1366 case M_IOCACK:
1367 case M_IOCNAK:
1369 * If we are doing an "ioctl" ourselves, check if this
1370 * is the reply to that code. If so, wake up the
1371 * "open" routine, and toss the reply, otherwise just
1372 * pass it up.
1374 iocp = (struct iocblk *)mp->b_rptr;
1375 if (!(kbdd->kbdd_flags & KBD_IOCWAIT) ||
1376 iocp->ioc_id != kbdd->kbdd_iocid) {
1378 * This isn't the reply we're looking for. Move along.
1380 if (kbdd->kbdd_flags & KBD_OPEN)
1381 putnext(q, mp);
1382 else
1383 freemsg(mp); /* not ready to listen */
1384 } else {
1385 kbdd->kbdd_flags &= ~KBD_IOCWAIT;
1386 kbdd->kbdd_iocerror = iocp->ioc_error;
1387 freemsg(mp);
1389 return;
1391 case M_DATA:
1392 if (!(kbdd->kbdd_flags & KBD_OPEN)) {
1393 freemsg(mp); /* not read to listen */
1394 return;
1396 break;
1400 * A data message, consisting of bytes from the keyboard.
1401 * Ram them through our state machine.
1403 bp = mp;
1405 do {
1406 readp = bp->b_rptr;
1407 while (readp < bp->b_wptr)
1408 kbdinput(kbdd, *readp++);
1409 bp->b_rptr = readp;
1410 } while ((bp = bp->b_cont) != NULL); /* next block, if any */
1412 freemsg(mp);
1416 * A keypress was received. Process it through the state machine
1417 * to check for aborts.
1419 static void
1420 kbdinput(register struct kbddata *kbdd, register unsigned key)
1422 register struct keyboardstate *k;
1423 register mblk_t *mp;
1425 k = &kbdd->kbdd_state;
1426 #ifdef KBD_DEBUG
1427 if (kbd_input_debug)
1428 printf("kbdinput key %x\n", key);
1429 #endif
1431 switch (k->k_idstate) {
1433 case KID_NONE:
1434 if (key == RESETKEY) {
1435 k->k_idstate = KID_GOT_PREFACE;
1436 } else {
1437 kbdreset(kbdd, HARD_RESET);
1438 /* allows hot plug of kbd after booting without kbd */
1440 return;
1442 case KID_GOT_PREFACE:
1443 kbdid(kbdd, (int)key);
1446 * We just did a reset command to a Type 3 or Type 4
1447 * keyboard which sets the click back to the default
1448 * (which is currently ON!). We use the kbdclick
1449 * variable to see if the keyboard should be turned on
1450 * or off. If it has not been set, then we use the
1451 * keyboard-click? property.
1453 switch (kbdclick) {
1454 case 0:
1455 kbdcmd(kbdd->kbdd_writeq, KBD_CMD_NOCLICK);
1456 break;
1457 case 1:
1458 kbdcmd(kbdd->kbdd_writeq, KBD_CMD_CLICK);
1459 break;
1460 case -1:
1461 default:
1463 char wrkbuf[8];
1464 int len;
1466 kbdcmd(kbdd->kbdd_writeq, KBD_CMD_NOCLICK);
1468 bzero(wrkbuf, 8);
1469 len = 7;
1470 if (ddi_getlongprop_buf(DDI_DEV_T_ANY,
1471 ddi_root_node(), 0, "keyboard-click?",
1472 (caddr_t)wrkbuf, &len) ==
1473 DDI_PROP_SUCCESS &&
1474 len > 0 && len < 8) {
1475 if (strcmp(wrkbuf, "true") == 0) {
1476 kbdcmd(kbdd->kbdd_writeq,
1477 KBD_CMD_CLICK);
1481 break;
1484 * A keyboard reset clears the LEDs.
1485 * Restore the LEDs from the last value we set
1486 * them to.
1488 kbdsetled(kbdd);
1489 return;
1491 case KID_OK:
1492 switch (key) {
1494 #if defined(KBD_PRESSED_PREFIX)
1495 case KBD_PRESSED_PREFIX:
1496 k->k_idstate = KID_GOT_PRESSED;
1497 return;
1498 #endif
1500 #if defined(KBD_RELEASED_PREFIX)
1501 case KBD_RELEASED_PREFIX:
1502 k->k_idstate = KID_GOT_RELEASED;
1503 return;
1504 #endif
1506 case 0:
1507 kbdreset(kbdd, HARD_RESET);
1508 return;
1511 * we want to check for ID only if we are in
1512 * translatable mode.
1514 case RESETKEY:
1515 kbdreset(kbdd, NO_HARD_RESET);
1516 if (k->k_idstate == KID_NONE) {
1517 k->k_idstate = KID_GOT_PREFACE;
1519 return;
1521 case LAYOUTKEY:
1522 k->k_idstate = KID_GOT_LAYOUT;
1523 return;
1525 break;
1527 #if defined(KBD_PRESSED_PREFIX)
1528 case KID_GOT_PRESSED:
1529 key = BUILDKEY(key, PRESSED);
1530 k->k_idstate = KID_OK;
1531 break;
1532 #endif
1533 #if defined(KBD_RELEASED_PREFIX)
1534 case KID_GOT_RELEASED:
1535 key = BUILDKEY(key, RELEASED);
1536 k->k_idstate = KID_OK;
1537 break;
1538 #endif
1540 case KID_GOT_LAYOUT:
1541 if (kbdd->kbdd_layoutid)
1542 (void) quntimeout(kbdd->kbdd_readq,
1543 kbdd->kbdd_layoutid);
1544 if ((mp = kbdd->kbdd_replypending) != NULL) {
1545 kbdd->kbdd_replypending = NULL;
1546 *(int *)mp->b_cont->b_wptr = key;
1547 mp->b_cont->b_wptr += sizeof (int);
1548 putnext(kbdd->kbdd_readq, mp);
1550 k->k_idstate = KID_OK;
1551 return;
1554 switch (k->k_state) {
1556 #if defined(__sparc)
1557 normalstate:
1558 k->k_state = NORMAL;
1559 /* FALLTHRU */
1560 #endif
1561 case NORMAL:
1562 #if defined(__sparc)
1563 if (k->k_curkeyboard) {
1564 if (key == k->k_curkeyboard->k_abort1) {
1565 k->k_state = ABORT1;
1566 break;
1568 if ((key == k->k_curkeyboard->k_newabort1) ||
1569 (key == k->k_curkeyboard->k_newabort1a)) {
1570 k->k_state = NEWABORT1;
1571 kbdd->shiftkey = key;
1574 #endif
1575 kbduse(kbdd, key);
1576 break;
1578 #if defined(__sparc)
1579 case ABORT1:
1580 if (k->k_curkeyboard) {
1582 * Only recognize this as an abort sequence if
1583 * the "hardware" console is set to be this device.
1585 if (key == k->k_curkeyboard->k_abort2 &&
1586 rconsvp == wsconsvp) {
1587 DELAY(100000);
1588 abort_sequence_enter((char *)NULL);
1589 k->k_state = NORMAL;
1590 kbduse(kbdd, IDLEKEY); /* fake */
1591 return;
1592 } else {
1593 kbduse(kbdd, k->k_curkeyboard->k_abort1);
1594 goto normalstate;
1597 break;
1598 case NEWABORT1:
1599 if (k->k_curkeyboard) {
1601 * Only recognize this as an abort sequence if
1602 * the "hardware" console is set to be this device.
1604 if (key == k->k_curkeyboard->k_newabort2 &&
1605 rconsvp == wsconsvp) {
1606 DELAY(100000);
1607 abort_sequence_enter((char *)NULL);
1608 k->k_state = NORMAL;
1609 kbdd->shiftkey |= RELEASED;
1610 kbduse(kbdd, kbdd->shiftkey);
1611 kbduse(kbdd, IDLEKEY); /* fake */
1612 return;
1613 } else {
1614 goto normalstate;
1617 break;
1618 #endif
1620 case COMPOSE1:
1621 case COMPOSE2:
1622 case FLTACCENT:
1623 if (key != IDLEKEY)
1624 kbduse(kbdd, key);
1625 break;
1629 static void
1630 kbdid(register struct kbddata *kbdd, int id)
1632 register struct keyboardstate *k;
1633 int i;
1635 k = &kbdd->kbdd_state;
1637 k->k_idstate = KID_OK;
1638 k->k_shiftmask = 0;
1639 k->k_buckybits = 0;
1642 * Reset k_rptkey to IDLEKEY. We need to cancel
1643 * the autorepeat feature, if any.
1645 if (k->k_rptkey != IDLEKEY) {
1646 if (kbdd->kbdd_rptid)
1647 (void) quntimeout(kbdd->kbdd_readq, kbdd->kbdd_rptid);
1648 kbdd->kbdd_rptid = 0;
1649 k->k_rptkey = IDLEKEY;
1652 k->k_curkeyboard = NULL;
1653 for (i = 0; keytables[i].table; i++) {
1654 if (keytables[i].id == id) {
1655 k->k_id = id;
1656 k->k_curkeyboard = keytables[i].table;
1657 break;
1660 if (!k->k_curkeyboard) {
1661 k->k_id = keytables[0].id;
1662 k->k_curkeyboard = keytables[0].table;
1663 cmn_err(CE_WARN, "kbd: Unknown keyboard type, "
1664 "Type %d assumed", k->k_id);
1669 * This routine determines which table we should look in to decode
1670 * the current keycode.
1672 static struct keymap *
1673 settable(register struct kbddata *kbdd, register uint_t mask)
1675 register struct keyboard *kp;
1677 kp = kbdd->kbdd_state.k_curkeyboard;
1678 if (kp == NULL)
1679 return (NULL);
1680 if (mask & UPMASK)
1681 return (kp->k_up);
1682 if (mask & NUMLOCKMASK)
1683 return (kp->k_numlock);
1684 if (mask & CTRLMASK)
1685 return (kp->k_control);
1686 if (mask & ALTGRAPHMASK)
1687 return (kp->k_altgraph);
1688 if (mask & SHIFTMASK)
1689 return (kp->k_shifted);
1690 if (mask & CAPSMASK)
1691 return (kp->k_caps);
1692 return (kp->k_normal);
1695 static void
1696 kbdrpt(void *arg)
1698 struct kbddata *kbdd = arg;
1699 struct keyboardstate *k;
1701 k = &kbdd->kbdd_state;
1702 #ifdef KBD_DEBUG
1703 if (kbd_rpt_debug)
1704 printf("kbdrpt key %x\n", k->k_rptkey);
1705 #endif
1706 kbdd->kbdd_rptid = 0;
1708 kbdkeyreleased(kbdd, KEYOF(k->k_rptkey));
1709 kbduse(kbdd, k->k_rptkey);
1710 if (k->k_rptkey != IDLEKEY) {
1711 kbdd->kbdd_rptid = qtimeout(kbdd->kbdd_readq, kbdrpt,
1712 kbdd, kbd_repeatrate);
1716 static void
1717 kbdcancelrpt(register struct kbddata *kbdd)
1719 register struct keyboardstate *k;
1721 k = &kbdd->kbdd_state;
1722 if (k->k_rptkey != IDLEKEY) {
1723 if (kbdd->kbdd_rptid)
1724 (void) quntimeout(kbdd->kbdd_readq, kbdd->kbdd_rptid);
1725 kbdd->kbdd_rptid = 0;
1726 k->k_rptkey = IDLEKEY;
1728 ASSERT(kbdd->kbdd_rptid == 0);
1731 static void
1732 kbdtranslate(struct kbddata *kbdd, unsigned keycode, queue_t *q)
1734 register uchar_t key;
1735 register unsigned newstate;
1736 unsigned shiftmask;
1737 register ushort_t entry, entrytype;
1738 register char *cp, *bufp;
1739 register struct keyboardstate *k;
1740 ushort_t result_iso;
1741 struct keymap *km;
1742 Firm_event fe;
1743 int i, ret_val;
1744 char buf[14];
1746 k = &kbdd->kbdd_state;
1747 newstate = STATEOF(keycode);
1748 key = KEYOF(keycode);
1750 #ifdef KBD_DEBUG
1751 if (kbd_input_debug) {
1752 printf("KBD TRANSLATE keycode=0x%x newstate=0x%x key=0x%x\n",
1753 keycode, newstate, key);
1755 #endif
1757 if (kbdd->kbdd_translate == TR_UNTRANS_EVENT) {
1758 if (newstate == PRESSED) {
1759 bzero(&fe, sizeof (fe));
1760 fe.id = key;
1761 fe.value = 1;
1762 kbdqueuepress(kbdd, key, &fe);
1763 } else {
1764 kbdkeyreleased(kbdd, key);
1766 return;
1769 shiftmask = k->k_shiftmask;
1770 if (newstate == RELEASED)
1771 shiftmask |= UPMASK;
1773 km = settable(kbdd, shiftmask);
1774 if (km == NULL) { /* gross error */
1775 kbdcancelrpt(kbdd);
1776 return;
1779 if (key >= KEYMAP_SIZE)
1780 return;
1781 entry = km->keymap[key];
1783 if (entry == NONL) {
1785 * NONL appears only in the Num Lock table, and indicates that
1786 * this key is not affected by Num Lock. This means we should
1787 * ask for the table we would have gotten had Num Lock not been
1788 * down, and translate using that table.
1790 km = settable(kbdd, shiftmask & ~NUMLOCKMASK);
1791 if (km == NULL) { /* gross error */
1792 kbdcancelrpt(kbdd);
1793 return;
1795 entry = km->keymap[key];
1797 entrytype = (ushort_t)(entry & 0xFF00) >> 8;
1799 if (entrytype == (SHIFTKEYS >> 8)) {
1801 * Handle the state of toggle shifts specially.
1802 * Ups should be ignored, and downs should be mapped to ups if
1803 * that shift is currently on.
1805 if ((1 << (entry & 0x0F)) & k->k_curkeyboard->k_toggleshifts) {
1806 if ((1 << (entry & 0x0F)) & k->k_togglemask) {
1807 newstate = RELEASED; /* toggling off */
1808 } else {
1809 newstate = PRESSED; /* toggling on */
1812 } else {
1814 * Handle Compose and floating accent key sequences
1816 if (k->k_state == COMPOSE1) {
1817 if (newstate == RELEASED)
1818 return;
1819 if (entry < ASCII_SET_SIZE) {
1820 if (kb_compose_map[entry] >= 0) {
1821 kbdd->compose_key = entry;
1822 k->k_state = COMPOSE2;
1823 return;
1826 k->k_state = NORMAL;
1827 kbdd->led_state &= ~LED_COMPOSE;
1828 kbdsetled(kbdd);
1829 return;
1830 } else if (k->k_state == COMPOSE2) {
1831 if (newstate == RELEASED)
1832 return;
1833 k->k_state = NORMAL; /* next state is "normal" */
1834 kbdd->led_state &= ~LED_COMPOSE;
1835 kbdsetled(kbdd);
1836 if (entry < ASCII_SET_SIZE) {
1837 if (kb_compose_map[entry] >= 0) {
1838 if (kbdd->compose_key <= entry) {
1839 ret_val = kbd_do_compose(
1840 kbdd->compose_key,
1841 entry,
1842 &result_iso);
1843 } else {
1844 ret_val = kbd_do_compose(
1845 entry,
1846 kbdd->compose_key,
1847 &result_iso);
1849 if (ret_val == 1) {
1850 if (kbdd->kbdd_translate ==
1851 TR_EVENT) {
1852 fe.id =
1853 (kbdd->kbdd_compat ?
1854 ISO_FIRST :
1855 EUC_FIRST)
1856 + result_iso;
1857 fe.value = 1;
1858 kbdqueueevent(
1859 kbdd,
1860 &fe);
1861 } else if (
1862 kbdd->kbdd_translate ==
1863 TR_ASCII)
1864 kbdputcode(
1865 result_iso,
1870 return;
1871 } else if (k->k_state == FLTACCENT) {
1872 if (newstate == RELEASED)
1873 return;
1874 k->k_state = NORMAL; /* next state is "normal" */
1875 for (i = 0;
1876 (kb_fltaccent_table[i].fa_entry
1877 != kbdd->fltaccent_entry) ||
1878 (kb_fltaccent_table[i].ascii != entry);
1879 i++) {
1880 if (kb_fltaccent_table[i].fa_entry == 0)
1881 /* Invalid second key: ignore key */
1882 return;
1884 if (kbdd->kbdd_translate == TR_EVENT) {
1885 fe.id = (kbdd->kbdd_compat ?
1886 ISO_FIRST : EUC_FIRST)
1887 + kb_fltaccent_table[i].iso;
1888 fe.value = 1;
1889 kbdqueueevent(kbdd, &fe);
1890 } else if (kbdd->kbdd_translate == TR_ASCII)
1891 kbdputcode(kb_fltaccent_table[i].iso, q);
1892 return;
1897 * If the key is going down, and it's not one of the keys that doesn't
1898 * auto-repeat, set up the auto-repeat timeout.
1900 * The keys that don't auto-repeat are the Compose key,
1901 * the shift keys, the "bucky bit" keys, the "floating accent" keys,
1902 * and the function keys when in TR_EVENT mode.
1904 if (newstate == PRESSED && entrytype != (SHIFTKEYS >> 8) &&
1905 entrytype != (BUCKYBITS >> 8) && entrytype != (FUNNY >> 8) &&
1906 entrytype != (FA_CLASS >> 8) &&
1907 !((entrytype == (FUNCKEYS >> 8) || entrytype == (PADKEYS >> 8)) &&
1908 kbdd->kbdd_translate == TR_EVENT)) {
1909 if (k->k_rptkey != keycode) {
1910 kbdcancelrpt(kbdd);
1911 kbdd->kbdd_rptid = qtimeout(q, kbdrpt, kbdd,
1912 kbd_repeatdelay);
1913 k->k_rptkey = keycode;
1915 } else if (key == KEYOF(k->k_rptkey)) /* key going up */
1916 kbdcancelrpt(kbdd);
1917 if ((newstate == RELEASED) && (kbdd->kbdd_translate == TR_EVENT))
1918 kbdkeyreleased(kbdd, key);
1921 * We assume here that keys other than shift keys and bucky keys have
1922 * entries in the "up" table that cause nothing to be done, and thus we
1923 * don't have to check for newstate == RELEASED.
1925 switch (entrytype) {
1927 case 0x0: /* regular key */
1928 switch (kbdd->kbdd_translate) {
1930 case TR_EVENT:
1931 fe.id = entry | k->k_buckybits;
1932 fe.value = 1;
1933 kbdkeypressed(kbdd, key, &fe, entry);
1934 break;
1936 case TR_ASCII:
1937 kbdputcode(entry | k->k_buckybits, q);
1938 break;
1940 break;
1942 case SHIFTKEYS >> 8: {
1943 uint_t shiftbit = 1 << (entry & 0x0F);
1945 /* Modify toggle state (see toggle processing above) */
1946 if (shiftbit & k->k_curkeyboard->k_toggleshifts) {
1947 if (newstate == RELEASED) {
1948 if (shiftbit == CAPSMASK) {
1949 kbdd->led_state &= ~LED_CAPS_LOCK;
1950 kbdsetled(kbdd);
1951 } else if (shiftbit == NUMLOCKMASK) {
1952 kbdd->led_state &= ~LED_NUM_LOCK;
1953 kbdsetled(kbdd);
1955 k->k_togglemask &= ~shiftbit;
1956 } else {
1957 if (shiftbit == CAPSMASK) {
1958 kbdd->led_state |= LED_CAPS_LOCK;
1959 kbdsetled(kbdd);
1960 } else if (shiftbit == NUMLOCKMASK) {
1961 kbdd->led_state |= LED_NUM_LOCK;
1962 kbdsetled(kbdd);
1964 k->k_togglemask |= shiftbit;
1968 if (newstate == RELEASED)
1969 k->k_shiftmask &= ~shiftbit;
1970 else
1971 k->k_shiftmask |= shiftbit;
1973 if (kbdd->kbdd_translate == TR_EVENT && newstate == PRESSED) {
1975 * Relying on ordinal correspondence between
1976 * vuid_event.h SHIFT_CAPSLOCK-SHIFT_RIGHTCTRL &
1977 * kbd.h CAPSLOCK-RIGHTCTRL in order to
1978 * correctly translate entry into fe.id.
1980 fe.id = SHIFT_CAPSLOCK + (entry & 0x0F);
1981 fe.value = 1;
1982 kbdkeypressed(kbdd, key, &fe, fe.id);
1984 break;
1987 case BUCKYBITS >> 8:
1988 k->k_buckybits ^= 1 << (7 + (entry & 0x0F));
1989 if (kbdd->kbdd_translate == TR_EVENT && newstate == PRESSED) {
1991 * Relying on ordinal correspondence between
1992 * vuid_event.h SHIFT_META-SHIFT_TOP &
1993 * kbd.h METABIT-SYSTEMBIT in order to
1994 * correctly translate entry into fe.id.
1996 fe.id = SHIFT_META + (entry & 0x0F);
1997 fe.value = 1;
1998 kbdkeypressed(kbdd, key, &fe, fe.id);
2000 break;
2002 case FUNNY >> 8:
2003 switch (entry) {
2004 case NOP:
2005 break;
2007 case IDLE:
2008 /* Fall thru into RESET code */
2009 /* FALLTHRU */
2010 case RESET:
2011 gotreset:
2012 k->k_shiftmask &= k->k_curkeyboard->k_idleshifts;
2013 k->k_shiftmask |= k->k_togglemask;
2014 k->k_buckybits &= k->k_curkeyboard->k_idlebuckys;
2015 kbdcancelrpt(kbdd);
2016 kbdreleaseall(kbdd);
2017 break;
2019 case ERROR:
2020 cmn_err(CE_WARN, "kbd: Error detected");
2021 goto gotreset;
2023 case COMPOSE:
2024 k->k_state = COMPOSE1;
2025 kbdd->led_state |= LED_COMPOSE;
2026 kbdsetled(kbdd);
2027 break;
2029 * Remember when adding new entries that,
2030 * if they should NOT auto-repeat,
2031 * they should be put into the IF statement
2032 * just above this switch block.
2034 default:
2035 goto badentry;
2037 break;
2039 case FA_CLASS >> 8:
2040 if (k->k_state == NORMAL) {
2041 kbdd->fltaccent_entry = entry;
2042 k->k_state = FLTACCENT;
2044 return;
2046 case STRING >> 8:
2047 cp = &keystringtab[entry & 0x0F][0];
2048 while (*cp != '\0') {
2049 switch (kbdd->kbdd_translate) {
2051 case TR_EVENT:
2052 kbd_send_esc_event(*cp, kbdd);
2053 break;
2055 case TR_ASCII:
2056 kbdputcode((uchar_t)*cp, q);
2057 break;
2059 cp++;
2061 break;
2063 case FUNCKEYS >> 8:
2064 switch (kbdd->kbdd_translate) {
2066 case TR_ASCII:
2067 bufp = buf;
2068 cp = strsetwithdecimal(bufp + 2,
2069 (uint_t)((entry & 0x003F) + 192),
2070 sizeof (buf) - 5);
2071 *bufp++ = '\033'; /* Escape */
2072 *bufp++ = '[';
2073 while (*cp != '\0')
2074 *bufp++ = *cp++;
2075 *bufp++ = 'z';
2076 *bufp = '\0';
2077 kbdputbuf(buf, q);
2078 break;
2080 case TR_EVENT:
2082 * Take advantage of the similar
2083 * ordering of kbd.h function keys and
2084 * vuid_event.h function keys to do a
2085 * simple translation to achieve a
2086 * mapping between the 2 different
2087 * address spaces.
2089 fe.id = (entry & 0x003F) + KEY_LEFTFIRST;
2090 fe.value = 1;
2092 * Assume "up" table only generates
2093 * shift changes.
2095 kbdkeypressed(kbdd, key, &fe, fe.id);
2097 * Function key events can be expanded
2098 * by terminal emulator software to
2099 * produce the standard escape sequence
2100 * generated by the TR_ASCII case above
2101 * if a function key event is not used
2102 * by terminal emulator software
2103 * directly.
2105 break;
2107 break;
2110 * Remember when adding new entries that,
2111 * if they should NOT auto-repeat,
2112 * they should be put into the IF statement
2113 * just above this switch block.
2115 case PADKEYS >> 8:
2116 switch (kbdd->kbdd_translate) {
2118 case TR_ASCII:
2119 kbdputcode(kb_numlock_table[entry&0x1F], q);
2120 break;
2122 case TR_EVENT:
2124 * Take advantage of the similar
2125 * ordering of kbd.h keypad keys and
2126 * vuid_event.h keypad keys to do a
2127 * simple translation to achieve a
2128 * mapping between the 2 different
2129 * address spaces.
2131 fe.id = (entry & 0x001F) + VKEY_FIRSTPAD;
2132 fe.value = 1;
2134 * Assume "up" table only generates
2135 * shift changes.
2137 kbdkeypressed(kbdd, key, &fe, fe.id);
2139 * Keypad key events can be expanded
2140 * by terminal emulator software to
2141 * produce the standard ascii character
2142 * generated by the TR_ASCII case above
2143 * if a keypad key event is not used
2144 * by terminal emulator software
2145 * directly.
2147 break;
2150 badentry:
2151 break;
2155 static int
2156 kbd_do_compose(ushort_t first_entry, ushort_t second_entry,
2157 ushort_t *result_iso_ptr)
2159 struct compose_sequence_t *ptr;
2161 ptr = &kb_compose_table[kb_compose_map[first_entry]];
2162 while (ptr->first == first_entry) {
2163 if (ptr->second == second_entry) {
2164 *result_iso_ptr = ptr->iso;
2165 return (1);
2167 ptr++;
2169 return (0);
2172 static void
2173 kbd_send_esc_event(char c, register struct kbddata *kbdd)
2175 Firm_event fe;
2177 fe.id = c;
2178 fe.value = 1;
2179 fe.pair_type = FE_PAIR_NONE;
2180 fe.pair = 0;
2182 * Pretend as if each cp pushed and released
2183 * Calling kbdqueueevent avoids addr translation
2184 * and pair base determination of kbdkeypressed.
2186 kbdqueueevent(kbdd, &fe);
2187 fe.value = 0;
2188 kbdqueueevent(kbdd, &fe);
2191 char *
2192 strsetwithdecimal(char *buf, uint_t val, uint_t maxdigs)
2194 int hradix = 5;
2195 char *bp;
2196 int lowbit;
2197 char *tab = "0123456789abcdef";
2199 bp = buf + maxdigs;
2200 *(--bp) = '\0';
2201 while (val) {
2202 lowbit = val & 1;
2203 val = (val >> 1);
2204 *(--bp) = tab[val % hradix * 2 + lowbit];
2205 val /= hradix;
2207 return (bp);
2210 static void
2211 kbdkeypressed(struct kbddata *kbdd, uchar_t key_station, Firm_event *fe,
2212 ushort_t base)
2214 register struct keyboardstate *k;
2215 register short id_addr;
2217 /* Set pair values */
2218 if (fe->id < (ushort_t)VKEY_FIRST) {
2220 * If CTRLed, find the ID that would have been used had it
2221 * not been CTRLed.
2223 k = &kbdd->kbdd_state;
2224 if (k->k_shiftmask & (CTRLMASK | CTLSMASK)) {
2225 struct keymap *km;
2227 km = settable(kbdd,
2228 k->k_shiftmask & ~(CTRLMASK | CTLSMASK | UPMASK));
2229 if (km == NULL)
2230 return;
2231 base = km->keymap[key_station];
2233 if (base != fe->id) {
2234 fe->pair_type = FE_PAIR_SET;
2235 fe->pair = base;
2236 goto send;
2239 fe->pair_type = FE_PAIR_NONE;
2240 fe->pair = 0;
2241 send:
2242 /* Adjust event id address for multiple keyboard/workstation support */
2243 switch (vuid_id_addr(fe->id)) {
2244 case ASCII_FIRST:
2245 id_addr = kbdd->kbdd_ascii_addr;
2246 break;
2247 case TOP_FIRST:
2248 id_addr = kbdd->kbdd_top_addr;
2249 break;
2250 case VKEY_FIRST:
2251 id_addr = kbdd->kbdd_vkey_addr;
2252 break;
2253 default:
2254 id_addr = vuid_id_addr(fe->id);
2256 fe->id = vuid_id_offset(fe->id) | id_addr;
2257 kbdqueuepress(kbdd, key_station, fe);
2260 static void
2261 kbdqueuepress(struct kbddata *kbdd, uchar_t key_station, Firm_event *fe)
2263 register struct key_event *ke, *ke_free;
2264 register int i;
2266 if (key_station == IDLEKEY)
2267 return;
2268 #ifdef KBD_DEBUG
2269 if (kbd_input_debug) printf("KBD PRESSED key=%d\n", key_station);
2270 #endif
2271 ke_free = 0;
2272 /* Scan table of down key stations */
2273 if (kbdd->kbdd_translate == TR_EVENT ||
2274 kbdd->kbdd_translate == TR_UNTRANS_EVENT) {
2275 for (i = 0, ke = kbdd->kbdd_downs;
2276 i < kbdd->kbdd_downs_entries;
2277 i++, ke++) {
2278 /* Keycode already down? */
2279 if (ke->key_station == key_station) {
2280 #ifdef KBD_DEBUG
2281 printf("kbd: Double entry in downs table (%d,%d)!\n", key_station, i);
2282 #endif
2283 goto add_event;
2285 if (ke->key_station == 0)
2286 ke_free = ke;
2288 if (ke_free) {
2289 ke = ke_free;
2290 goto add_event;
2292 cmn_err(CE_WARN, "kbd: Too many keys down!");
2293 ke = kbdd->kbdd_downs;
2295 add_event:
2296 ke->key_station = key_station;
2297 ke->event = *fe;
2298 kbdqueueevent(kbdd, fe);
2301 static void
2302 kbdkeyreleased(register struct kbddata *kbdd, uchar_t key_station)
2304 register struct key_event *ke;
2305 register int i;
2307 if (key_station == IDLEKEY)
2308 return;
2309 #ifdef KBD_DEBUG
2310 if (kbd_input_debug)
2311 printf("KBD RELEASE key=%d\n", key_station);
2312 #endif
2313 if (kbdd->kbdd_translate != TR_EVENT &&
2314 kbdd->kbdd_translate != TR_UNTRANS_EVENT)
2315 return;
2316 /* Scan table of down key stations */
2317 for (i = 0, ke = kbdd->kbdd_downs;
2318 i < kbdd->kbdd_downs_entries;
2319 i++, ke++) {
2320 /* Found? */
2321 if (ke->key_station == key_station) {
2322 ke->key_station = 0;
2323 ke->event.value = 0;
2324 kbdqueueevent(kbdd, &ke->event);
2329 * Ignore if couldn't find because may be called twice
2330 * for the same key station in the case of the kbdrpt
2331 * routine being called unnecessarily.
2335 static void
2336 kbdreleaseall(struct kbddata *kbdd)
2338 register struct key_event *ke;
2339 register int i;
2341 #ifdef KBD_DEBUG
2342 if (kbd_debug && kbd_ra_debug) printf("KBD RELEASE ALL\n");
2343 #endif
2344 /* Scan table of down key stations */
2345 for (i = 0, ke = kbdd->kbdd_downs;
2346 i < kbdd->kbdd_downs_entries; i++, ke++) {
2347 /* Key station not zero */
2348 if (ke->key_station)
2349 kbdkeyreleased(kbdd, ke->key_station);
2350 /* kbdkeyreleased resets kbdd_downs entry */
2355 * Pass a keycode up the stream, if you can, otherwise throw it away.
2357 static void
2358 kbdputcode(uint_t code, queue_t *q)
2360 register mblk_t *bp;
2362 if (!canput(q))
2363 cmn_err(CE_WARN, "kbdputcode: Can't put block for keycode");
2364 else {
2365 if ((bp = allocb(sizeof (uint_t), BPRI_HI)) == NULL)
2366 cmn_err(CE_WARN,
2367 "kbdputcode: Can't allocate block for keycode");
2368 else {
2369 *bp->b_wptr++ = code;
2370 putnext(q, bp);
2376 * Pass generated keycode sequence to upstream, if possible.
2378 static void
2379 kbdputbuf(char *buf, queue_t *q)
2381 register mblk_t *bp;
2383 if (!canput(q))
2384 cmn_err(CE_WARN, "kbdputbuf: Can't put block for keycode");
2385 else {
2386 if ((bp = allocb((int)strlen(buf), BPRI_HI)) == NULL)
2387 cmn_err(CE_WARN,
2388 "kbdputbuf: Can't allocate block for keycode");
2389 else {
2390 while (*buf) {
2391 *bp->b_wptr++ = *buf;
2392 buf++;
2394 putnext(q, bp);
2400 * Pass a VUID "firm event" up the stream, if you can.
2402 static void
2403 kbdqueueevent(struct kbddata *kbdd, Firm_event *fe)
2405 register queue_t *q;
2406 register mblk_t *bp;
2408 if ((q = kbdd->kbdd_readq) == NULL)
2409 return;
2410 if (!canput(q)) {
2411 if (kbd_overflow_msg)
2412 cmn_err(CE_WARN,
2413 "kbd: Buffer flushed when overflowed");
2414 kbdflush(kbdd);
2415 kbd_overflow_cnt++;
2416 } else {
2417 if ((bp = allocb(sizeof (Firm_event), BPRI_HI)) == NULL)
2418 cmn_err(CE_WARN,
2419 "kbdqueueevent: Can't allocate block for event");
2420 else {
2421 #if 1 /* XX64 */
2422 struct timeval now;
2425 * XX64: This is something of a compromise. It
2426 * seems justifiable based on the usage of these
2427 * timestamps as an ordering relation as opposed
2428 * to a strict timing thing.
2430 * But should we restore Firm_event's time stamp
2431 * to be a timeval, and send 32-bit and 64-bit
2432 * events up the pipe?
2434 uniqtime(&now);
2435 TIMEVAL_TO_TIMEVAL32(&fe->time, &now);
2436 #else
2437 uniqtime(&fe->time);
2438 #endif
2439 *(Firm_event *)bp->b_wptr = *fe;
2440 bp->b_wptr += sizeof (Firm_event);
2441 putnext(q, bp);