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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27 /* SunOS-4.0 1.60 */
28 /* From: SunOS4.0 sundev/kbd.c */
29
30 /*
31 * Keyboard input streams module - handles conversion of up/down codes to
32 * ASCII or event format.
33 */
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>
57
58 #include <sys/modctl.h>
59 #include <sys/beep.h>
60 #include <sys/int_limits.h>
61
62 static struct streamtab kbd_info;
63
64 static struct fmodsw fsw = {
65 "kb",
66 &kbd_info,
67 D_MP | D_MTPERMOD
68 };
69
70 /*
71 * Module linkage information for the kernel.
72 */
73
74 static struct modlstrmod modlstrmod = {
75 &mod_strmodops, "streams module for keyboard", &fsw
76 };
77
78 static struct modlinkage modlinkage = {
79 MODREV_1, (void *)&modlstrmod, NULL
80 };
81
82 int
_init(void)83 _init(void)
84 {
85 return (mod_install(&modlinkage));
86 }
87
88 int
_fini(void)89 _fini(void)
90 {
91 return (mod_remove(&modlinkage));
92 }
93
94 int
_info(struct modinfo * modinfop)95 _info(struct modinfo *modinfop)
96 {
97 return (mod_info(&modlinkage, modinfop));
98 }
99
100 /*
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.
104 */
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[];
111
112 /*
113 * This value corresponds approximately to max 10 fingers
114 */
115 static int kbd_downs_size = 15;
116
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;
133 /*
134 * State of keyboard & keyboard
135 * specific settings, e.g., tables
136 */
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;
144 /*
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
149 */
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 */
156 };
157
158 #define KBD_OPEN 0x00000001 /* keyboard is open for business */
159 #define KBD_IOCWAIT 0x00000002 /* "open" waiting for "ioctl" to finish */
160
161 #define NO_HARD_RESET 0 /* don't do hard reset */
162 #define HARD_RESET 1 /* do hard reset */
163
164
165 /*
166 * Constants setup during the first open of a kbd (so that they can be patched
167 * for debugging purposes).
168 */
169 static int kbd_repeatrate;
170 static int kbd_repeatdelay;
171
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 */
174
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 */
182
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 *);
187
188 static struct module_info kbdmiinfo = {
189 0,
190 "kb",
191 0,
192 INFPSZ,
193 2048,
194 128
195 };
196
197 static struct qinit kbdrinit = {
198 (int (*)())kbdrput,
199 (int (*)())NULL,
200 kbdopen,
201 kbdclose,
202 (int (*)())NULL,
203 &kbdmiinfo
204 };
205
206 static struct module_info kbdmoinfo = {
207 0,
208 "kb",
209 0,
210 INFPSZ,
211 2048,
212 128
213 };
214
215 static struct qinit kbdwinit = {
216 (int (*)())kbdwput,
217 (int (*)())NULL,
218 kbdopen,
219 kbdclose,
220 (int (*)())NULL,
221 &kbdmoinfo
222 };
223
224 static struct streamtab kbd_info = {
225 &kbdrinit,
226 &kbdwinit,
227 NULL,
228 NULL,
229 };
230
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 *);
262
263 /*
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).)
271 */
272 /* ARGSUSED */
dummy_callback(void * arg)273 static void dummy_callback(void *arg)
274 {}
275
276
277 /*
278 * Open a keyboard.
279 * Ttyopen sets line characteristics
280 */
281 /* ARGSUSED */
282 static int
kbdopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * crp)283 kbdopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
284 {
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;
291
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;
296 }
297
298 if (q->q_ptr != NULL)
299 return (0); /* already attached */
300
301 /*
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.
305 */
306 if (secpolicy_console(crp) != 0) {
307 return (EPERM);
308 }
309
310
311 switch (sflag) {
312
313 case MODOPEN:
314 break;
315
316 case CLONEOPEN:
317 return (EINVAL); /* No Bozos! */
318 }
319
320 /* allocate keyboard */
321
322 kbdd = kmem_zalloc(sizeof (struct kbddata), KM_SLEEP);
323
324
325 /*
326 * Set up queue pointers, so that the "put" procedure will accept
327 * the reply to the "ioctl" message we send down.
328 */
329 q->q_ptr = kbdd;
330 WR(q)->q_ptr = kbdd;
331
332 qprocson(q);
333
334 /*
335 * Setup tty modes.
336 */
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);
344
345 return (EINTR);
346 }
347 }
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);
357
358 return (EINTR);
359 }
360 }
361
362 iocb = (struct iocblk *)mp->b_rptr;
363 iocb->ioc_count = sizeof (struct termios);
364
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);
376
377 /*
378 * Now wait for it. Let our read queue put routine wake us up
379 * when it arrives.
380 */
381 while (kbdd->kbdd_flags & KBD_IOCWAIT) {
382 if (!qwait_sig(q)) {
383 error = EINTR;
384 goto error;
385 }
386 }
387 if ((error = kbdd->kbdd_iocerror) != 0)
388 goto error;
389
390 /*
391 * Set up private data.
392 */
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;
408
409 /*
410 * Reset kbd.
411 */
412 kbdreset(kbdd, HARD_RESET);
413
414 (void) beep_init((void *)WR(q), kbd_beep_on, kbd_beep_off, NULL);
415
416 return (0);
417
418 error:
419 qprocsoff(q);
420 kmem_free(kbdd, sizeof (struct kbddata));
421 return (error);
422 }
423
424 /*
425 * Close a keyboard.
426 */
427 /* ARGSUSED1 */
428 static int
kbdclose(register queue_t * q,int flag,cred_t * crp)429 kbdclose(register queue_t *q, int flag, cred_t *crp)
430 {
431 register struct kbddata *kbdd = (struct kbddata *)q->q_ptr;
432 register mblk_t *mp;
433
434 qprocsoff(q);
435 (void) beep_fini();
436 /*
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.
440 */
441 kbdd->kbdd_flags = 0;
442
443 if ((mp = kbdd->kbdd_replypending) != NULL) {
444 /*
445 * There was a KIOCLAYOUT pending; presumably, it timed out.
446 * Throw the reply away.
447 */
448 kbdd->kbdd_replypending = NULL;
449 freemsg(mp);
450 }
451
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);
462 }
463
464 /*
465 * Line discipline output queue put procedure: handles M_IOCTL
466 * messages.
467 */
468 static void
kbdwput(register queue_t * q,register mblk_t * mp)469 kbdwput(register queue_t *q, register mblk_t *mp)
470 {
471 /*
472 * Process M_FLUSH, and some M_IOCTL, messages here; pass
473 * everything else down.
474 */
475 switch (mp->b_datap->db_type) {
476
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);
482
483 default:
484 putnext(q, mp); /* pass it down the line */
485 break;
486
487 case M_IOCTL:
488 kbdioctl(q, mp);
489 break;
490 }
491 }
492
493
494 static void
kbdreioctl(void * kbdd_addr)495 kbdreioctl(void *kbdd_addr)
496 {
497 struct kbddata *kbdd = kbdd_addr;
498 queue_t *q;
499 mblk_t *mp;
500
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);
506 }
507 }
508
509 static void
kbdioctl(register queue_t * q,register mblk_t * mp)510 kbdioctl(register queue_t *q, register mblk_t *mp)
511 {
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;
524
525 iocp = (struct iocblk *)mp->b_rptr;
526
527 switch (iocp->ioc_cmd) {
528
529 case VUIDSFORMAT:
530 err = miocpullup(mp, sizeof (int));
531 if (err != 0)
532 break;
533
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;
540
541 case KIOCTRANS:
542 err = miocpullup(mp, sizeof (int));
543 if (err != 0)
544 break;
545
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;
551
552 case KIOCCMD:
553 err = miocpullup(mp, sizeof (int));
554 if (err != 0)
555 break;
556
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;
565
566 case KIOCMKTONE:
567 if (iocp->ioc_count != TRANSPARENT) {
568 /*
569 * We don't support non-transparent ioctls,
570 * i.e. I_STR ioctls
571 */
572 err = EINVAL;
573 break;
574 }
575 tmp = (int)(*(intptr_t *)mp->b_cont->b_rptr);
576 cycles = tmp & 0xffff;
577 msecs = (tmp >> 16) & 0xffff;
578
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;
587 }
588
589 err = beep_mktone(frequency, msecs);
590 break;
591
592 case KIOCSLED:
593 err = miocpullup(mp, sizeof (uchar_t));
594 if (err != 0)
595 break;
596
597 kbdd->led_state = *(uchar_t *)mp->b_cont->b_rptr;
598 kbdsetled(kbdd);
599 break;
600
601 case KIOCGLED:
602 if ((datap = allocb(sizeof (uchar_t), BPRI_HI)) == NULL) {
603 ioctlrespsize = sizeof (int);
604 goto allocfailure;
605 }
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;
613
614 case VUIDGFORMAT:
615 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
616 ioctlrespsize = sizeof (int);
617 goto allocfailure;
618 }
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;
629
630 case KIOCGTRANS:
631 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
632 ioctlrespsize = sizeof (int);
633 goto allocfailure;
634 }
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;
642
643 case VUIDSADDR:
644 err = miocpullup(mp, sizeof (Vuid_addr_probe));
645 if (err != 0)
646 break;
647
648 addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
649 switch (addr_probe->base) {
650
651 case ASCII_FIRST:
652 addr_ptr = &kbdd->kbdd_ascii_addr;
653 break;
654
655 case TOP_FIRST:
656 addr_ptr = &kbdd->kbdd_top_addr;
657 break;
658
659 case VKEY_FIRST:
660 addr_ptr = &kbdd->kbdd_vkey_addr;
661 break;
662
663 default:
664 err = ENODEV;
665 }
666 if ((err == 0) && (*addr_ptr != addr_probe->data.next)) {
667 *addr_ptr = addr_probe->data.next;
668 goto output_format_change;
669 }
670 break;
671
672 case VUIDGADDR:
673 err = miocpullup(mp, sizeof (Vuid_addr_probe));
674 if (err != 0)
675 break;
676
677 addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
678 switch (addr_probe->base) {
679
680 case ASCII_FIRST:
681 addr_probe->data.current = kbdd->kbdd_ascii_addr;
682 break;
683
684 case TOP_FIRST:
685 addr_probe->data.current = kbdd->kbdd_top_addr;
686 break;
687
688 case VKEY_FIRST:
689 addr_probe->data.current = kbdd->kbdd_vkey_addr;
690 break;
691
692 default:
693 err = ENODEV;
694 }
695 break;
696
697 case KIOCTRANSABLE:
698 err = miocpullup(mp, sizeof (int));
699 if (err != 0)
700 break;
701
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;
706 }
707 break;
708
709 case KIOCGTRANSABLE:
710 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
711 ioctlrespsize = sizeof (int);
712 goto allocfailure;
713 }
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;
721
722 case KIOCSCOMPAT:
723 err = miocpullup(mp, sizeof (int));
724 if (err != 0)
725 break;
726
727 kbdd->kbdd_compat = *(int *)mp->b_cont->b_rptr;
728 break;
729
730 case KIOCGCOMPAT:
731 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
732 ioctlrespsize = sizeof (int);
733 goto allocfailure;
734 }
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;
742
743 case KIOCSETKEY:
744 err = miocpullup(mp, sizeof (struct kiockey));
745 if (err != 0)
746 break;
747
748 err = kbdsetkey(kbdd, (struct kiockey *)mp->b_cont->b_rptr,
749 iocp->ioc_cr);
750 /*
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.
754 */
755 break;
756
757 case KIOCGETKEY:
758 err = miocpullup(mp, sizeof (struct kiockey));
759 if (err != 0)
760 break;
761
762 err = kbdgetkey(kbdd, (struct kiockey *)mp->b_cont->b_rptr);
763 break;
764
765 case KIOCSKEY:
766 err = miocpullup(mp, sizeof (struct kiockeymap));
767 if (err != 0)
768 break;
769
770 err = kbdskey(kbdd, (struct kiockeymap *)mp->b_cont->b_rptr,
771 iocp->ioc_cr);
772 /*
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.
776 */
777 break;
778
779 case KIOCGKEY:
780 err = miocpullup(mp, sizeof (struct kiockeymap));
781 if (err != 0)
782 break;
783
784 err = kbdgkey(kbdd, (struct kiockeymap *)mp->b_cont->b_rptr);
785 break;
786
787 case KIOCSDIRECT:
788 goto output_format_change;
789
790 case KIOCGDIRECT:
791 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
792 ioctlrespsize = sizeof (int);
793 goto allocfailure;
794 }
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;
802
803 case KIOCTYPE:
804 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
805 ioctlrespsize = sizeof (int);
806 goto allocfailure;
807 }
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;
815
816 case KIOCLAYOUT:
817 if ((datap = kbdd->kbdd_replypending) != NULL) {
818 /*
819 * There was an earlier KIOCLAYOUT pending; presumably,
820 * it timed out. Throw the reply away.
821 */
822 kbdd->kbdd_replypending = NULL;
823 freemsg(datap);
824 }
825
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;
831 }
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 {
847 /*
848 * Not a Type 4 keyboard; return an immediate error.
849 */
850 err = EINVAL;
851 break;
852 }
853
854 case KIOCGRPTDELAY:
855 /*
856 * Report the autorepeat delay, unit in millisecond
857 */
858 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
859 ioctlrespsize = sizeof (int);
860 goto allocfailure;
861 }
862 *(int *)datap->b_wptr = TICK_TO_MSEC(kbd_repeatdelay);
863 datap->b_wptr += sizeof (int);
864
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;
871
872 case KIOCSRPTDELAY:
873 /*
874 * Set the autorepeat delay
875 */
876 err = miocpullup(mp, sizeof (int));
877
878 if (err != 0)
879 break;
880
881 /* validate the input */
882 if (*(int *)mp->b_cont->b_rptr < KIOCRPTDELAY_MIN) {
883 err = EINVAL;
884 break;
885 }
886 kbd_repeatdelay = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
887 if (kbd_repeatdelay <= 0)
888 kbd_repeatdelay = 1;
889 break;
890
891 case KIOCGRPTRATE:
892 /*
893 * Report the autorepeat rate
894 */
895 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
896 ioctlrespsize = sizeof (int);
897 goto allocfailure;
898 }
899 *(int *)datap->b_wptr = TICK_TO_MSEC(kbd_repeatrate);
900 datap->b_wptr += sizeof (int);
901
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;
908
909 case KIOCSRPTRATE:
910 /*
911 * Set the autorepeat rate
912 */
913 err = miocpullup(mp, sizeof (int));
914
915 if (err != 0)
916 break;
917
918 /* validate the input */
919 if (*(int *)mp->b_cont->b_rptr < KIOCRPTRATE_MIN) {
920 err = EINVAL;
921 break;
922 }
923 kbd_repeatrate = MSEC_TO_TICK(*(int *)mp->b_cont->b_rptr);
924 if (kbd_repeatrate <= 0)
925 kbd_repeatrate = 1;
926 break;
927
928 default:
929 putnext(q, mp); /* pass it down the line */
930 return;
931 }
932 goto done;
933
934 output_format_change:
935 kbdflush(kbdd);
936
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;
946 }
947 qreply(q, mp);
948 return;
949
950 allocfailure:
951 /*
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.
957 */
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);
965 }
966
967 static void
kbdflush(register struct kbddata * kbdd)968 kbdflush(register struct kbddata *kbdd)
969 {
970 register queue_t *q;
971
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);
978 }
979
980 /*
981 * Pass keycode upstream, either translated or untranslated.
982 */
983 static void
kbduse(register struct kbddata * kbdd,unsigned keycode)984 kbduse(register struct kbddata *kbdd, unsigned keycode)
985 {
986 register queue_t *readq;
987
988 #ifdef KBD_DEBUG
989 if (kbd_input_debug) printf("KBD USE key=%d\n", keycode);
990 #endif
991
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);
999 }
1000
1001 static void
kbd_beep_on(void * arg)1002 kbd_beep_on(void *arg)
1003 {
1004 kbdcmd((queue_t *)arg, KBD_CMD_BELL);
1005 }
1006
1007
1008 static void
kbd_beep_off(void * arg)1009 kbd_beep_off(void *arg)
1010 {
1011 kbdcmd((queue_t *)arg, KBD_CMD_NOBELL);
1012 }
1013
1014
1015 /*
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.
1026 */
1027 static int kbdclick = -1;
1028
1029 /*
1030 * Send command byte to keyboard, if you can.
1031 */
1032 static void
kbdcmd(register queue_t * q,char cmd)1033 kbdcmd(register queue_t *q, char cmd)
1034 {
1035 register mblk_t *bp;
1036
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;
1048 }
1049 }
1050 }
1051
1052 /*
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).
1056 */
1057 static void
kbdsetled(register struct kbddata * kbdd)1058 kbdsetled(register struct kbddata *kbdd)
1059 {
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);
1064 }
1065 }
1066
1067 /*
1068 * Reset the keyboard
1069 */
1070 static void
kbdreset(register struct kbddata * kbdd,uint_t hard_reset)1071 kbdreset(register struct kbddata *kbdd, uint_t hard_reset)
1072 {
1073 register struct keyboardstate *k;
1074
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;
1086 }
1087 }
1088
1089 /*
1090 * Old special codes.
1091 */
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
1107
1108 /*
1109 * Map old special codes to new ones.
1110 * Indexed by ((old special code) >> 4) & 0x07; add (old special code) & 0x0F.
1111 */
1112 static ushort_t special_old_to_new[] = {
1113 SHIFTKEYS,
1114 BUCKYBITS,
1115 FUNNY,
1116 STRING,
1117 LEFTFUNC,
1118 RIGHTFUNC,
1119 TOPFUNC,
1120 BOTTOMFUNC,
1121 };
1122
1123 /*
1124 * Set individual keystation translation from old-style entry.
1125 * TODO: Have each keyboard own own translation tables.
1126 */
1127 static int
kbdsetkey(register struct kbddata * kbdd,struct kiockey * key,cred_t * cr)1128 kbdsetkey(register struct kbddata *kbdd, struct kiockey *key, cred_t *cr)
1129 {
1130 int strtabindex, i;
1131 struct keymap *km;
1132 register int tablemask;
1133 register ushort_t entry;
1134
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);
1145 }
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);
1151 }
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';
1161 }
1162 entry = key->kio_entry;
1163 /*
1164 * There's nothing we need do with OLD_ISOCHAR.
1165 */
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);
1174 }
1175 }
1176 km->keymap[key->kio_station] = entry;
1177 return (0);
1178 }
1179
1180 /*
1181 * Map new special codes to old ones.
1182 * Indexed by (new special code) >> 8; add (new special code) & 0xFF.
1183 */
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 */
1192 };
1193
1194 /*
1195 * Get individual keystation translation as old-style entry.
1196 */
1197 static int
kbdgetkey(register struct kbddata * kbdd,struct kiockey * key)1198 kbdgetkey(register struct kbddata *kbdd, struct kiockey *key)
1199 {
1200 int strtabindex, i;
1201 struct keymap *km;
1202 register ushort_t entry;
1203
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);
1211 }
1212 if (key->kio_tablemask == KIOCABORT2) {
1213 key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort2;
1214 return (0);
1215 }
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;
1228 }
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];
1233 }
1234 return (0);
1235 }
1236
1237 /*
1238 * Set individual keystation translation from new-style entry.
1239 * TODO: Have each keyboard own own translation tables.
1240 */
1241 static int
kbdskey(register struct kbddata * kbdd,struct kiockeymap * key,cred_t * cr)1242 kbdskey(register struct kbddata *kbdd, struct kiockeymap *key, cred_t *cr)
1243 {
1244 int strtabindex, i;
1245 struct keymap *km;
1246
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);
1256 }
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);
1262 }
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';
1271 }
1272 km->keymap[key->kio_station] = key->kio_entry;
1273 return (0);
1274 }
1275
1276 /*
1277 * Get individual keystation translation as new-style entry.
1278 */
1279 static int
kbdgkey(register struct kbddata * kbdd,struct kiockeymap * key)1280 kbdgkey(register struct kbddata *kbdd, struct kiockeymap *key)
1281 {
1282 int strtabindex, i;
1283 struct keymap *km;
1284
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);
1292 }
1293 if (key->kio_tablemask == KIOCABORT2) {
1294 key->kio_station = kbdd->kbdd_state.k_curkeyboard->k_abort2;
1295 return (0);
1296 }
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];
1305 }
1306 return (0);
1307 }
1308
1309 static void
kbdlayouttimeout(void * arg)1310 kbdlayouttimeout(void *arg)
1311 {
1312 struct kbddata *kbdd = arg;
1313 mblk_t *mp;
1314
1315 kbdd->kbdd_layoutid = 0;
1316
1317 /*
1318 * Timed out waiting for reply to "get keyboard layout" command.
1319 * Return an ETIME error.
1320 */
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);
1326 }
1327 }
1328
1329 /*
1330 * Put procedure for input from driver end of stream (read queue).
1331 */
1332 static void
kbdrput(register queue_t * q,register mblk_t * mp)1333 kbdrput(register queue_t *q, register mblk_t *mp)
1334 {
1335 struct kbddata *kbdd = (struct kbddata *)q->q_ptr;
1336 register mblk_t *bp;
1337 register uchar_t *readp;
1338 struct iocblk *iocp;
1339
1340 if (kbdd == 0) {
1341 freemsg(mp); /* nobody's listening */
1342 return;
1343 }
1344
1345 switch (mp->b_datap->db_type) {
1346
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);
1352
1353 default:
1354 putnext(q, mp);
1355 return;
1356
1357 case M_BREAK:
1358 /*
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.
1362 */
1363 freemsg(mp);
1364 return;
1365
1366 case M_IOCACK:
1367 case M_IOCNAK:
1368 /*
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.
1373 */
1374 iocp = (struct iocblk *)mp->b_rptr;
1375 if (!(kbdd->kbdd_flags & KBD_IOCWAIT) ||
1376 iocp->ioc_id != kbdd->kbdd_iocid) {
1377 /*
1378 * This isn't the reply we're looking for. Move along.
1379 */
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);
1388 }
1389 return;
1390
1391 case M_DATA:
1392 if (!(kbdd->kbdd_flags & KBD_OPEN)) {
1393 freemsg(mp); /* not read to listen */
1394 return;
1395 }
1396 break;
1397 }
1398
1399 /*
1400 * A data message, consisting of bytes from the keyboard.
1401 * Ram them through our state machine.
1402 */
1403 bp = mp;
1404
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 */
1411
1412 freemsg(mp);
1413 }
1414
1415 /*
1416 * A keypress was received. Process it through the state machine
1417 * to check for aborts.
1418 */
1419 static void
kbdinput(register struct kbddata * kbdd,register unsigned key)1420 kbdinput(register struct kbddata *kbdd, register unsigned key)
1421 {
1422 register struct keyboardstate *k;
1423 register mblk_t *mp;
1424
1425 k = &kbdd->kbdd_state;
1426 #ifdef KBD_DEBUG
1427 if (kbd_input_debug)
1428 printf("kbdinput key %x\n", key);
1429 #endif
1430
1431 switch (k->k_idstate) {
1432
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 */
1439 }
1440 return;
1441
1442 case KID_GOT_PREFACE:
1443 kbdid(kbdd, (int)key);
1444
1445 /*
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.
1452 */
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:
1462 {
1463 char wrkbuf[8];
1464 int len;
1465
1466 kbdcmd(kbdd->kbdd_writeq, KBD_CMD_NOCLICK);
1467
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);
1478 }
1479 }
1480 }
1481 break;
1482 }
1483 /*
1484 * A keyboard reset clears the LEDs.
1485 * Restore the LEDs from the last value we set
1486 * them to.
1487 */
1488 kbdsetled(kbdd);
1489 return;
1490
1491 case KID_OK:
1492 switch (key) {
1493
1494 #if defined(KBD_PRESSED_PREFIX)
1495 case KBD_PRESSED_PREFIX:
1496 k->k_idstate = KID_GOT_PRESSED;
1497 return;
1498 #endif
1499
1500 #if defined(KBD_RELEASED_PREFIX)
1501 case KBD_RELEASED_PREFIX:
1502 k->k_idstate = KID_GOT_RELEASED;
1503 return;
1504 #endif
1505
1506 case 0:
1507 kbdreset(kbdd, HARD_RESET);
1508 return;
1509
1510 /*
1511 * we want to check for ID only if we are in
1512 * translatable mode.
1513 */
1514 case RESETKEY:
1515 kbdreset(kbdd, NO_HARD_RESET);
1516 if (k->k_idstate == KID_NONE) {
1517 k->k_idstate = KID_GOT_PREFACE;
1518 }
1519 return;
1520
1521 case LAYOUTKEY:
1522 k->k_idstate = KID_GOT_LAYOUT;
1523 return;
1524 }
1525 break;
1526
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
1539
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);
1549 }
1550 k->k_idstate = KID_OK;
1551 return;
1552 }
1553
1554 switch (k->k_state) {
1555
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;
1567 }
1568 if ((key == k->k_curkeyboard->k_newabort1) ||
1569 (key == k->k_curkeyboard->k_newabort1a)) {
1570 k->k_state = NEWABORT1;
1571 kbdd->shiftkey = key;
1572 }
1573 }
1574 #endif
1575 kbduse(kbdd, key);
1576 break;
1577
1578 #if defined(__sparc)
1579 case ABORT1:
1580 if (k->k_curkeyboard) {
1581 /*
1582 * Only recognize this as an abort sequence if
1583 * the "hardware" console is set to be this device.
1584 */
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;
1595 }
1596 }
1597 break;
1598 case NEWABORT1:
1599 if (k->k_curkeyboard) {
1600 /*
1601 * Only recognize this as an abort sequence if
1602 * the "hardware" console is set to be this device.
1603 */
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;
1615 }
1616 }
1617 break;
1618 #endif
1619
1620 case COMPOSE1:
1621 case COMPOSE2:
1622 case FLTACCENT:
1623 if (key != IDLEKEY)
1624 kbduse(kbdd, key);
1625 break;
1626 }
1627 }
1628
1629 static void
kbdid(register struct kbddata * kbdd,int id)1630 kbdid(register struct kbddata *kbdd, int id)
1631 {
1632 register struct keyboardstate *k;
1633 int i;
1634
1635 k = &kbdd->kbdd_state;
1636
1637 k->k_idstate = KID_OK;
1638 k->k_shiftmask = 0;
1639 k->k_buckybits = 0;
1640
1641 /*
1642 * Reset k_rptkey to IDLEKEY. We need to cancel
1643 * the autorepeat feature, if any.
1644 */
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;
1650 }
1651
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;
1658 }
1659 }
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);
1665 }
1666 }
1667
1668 /*
1669 * This routine determines which table we should look in to decode
1670 * the current keycode.
1671 */
1672 static struct keymap *
settable(register struct kbddata * kbdd,register uint_t mask)1673 settable(register struct kbddata *kbdd, register uint_t mask)
1674 {
1675 register struct keyboard *kp;
1676
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);
1693 }
1694
1695 static void
kbdrpt(void * arg)1696 kbdrpt(void *arg)
1697 {
1698 struct kbddata *kbdd = arg;
1699 struct keyboardstate *k;
1700
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;
1707
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);
1713 }
1714 }
1715
1716 static void
kbdcancelrpt(register struct kbddata * kbdd)1717 kbdcancelrpt(register struct kbddata *kbdd)
1718 {
1719 register struct keyboardstate *k;
1720
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;
1727 }
1728 ASSERT(kbdd->kbdd_rptid == 0);
1729 }
1730
1731 static void
kbdtranslate(struct kbddata * kbdd,unsigned keycode,queue_t * q)1732 kbdtranslate(struct kbddata *kbdd, unsigned keycode, queue_t *q)
1733 {
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];
1745
1746 k = &kbdd->kbdd_state;
1747 newstate = STATEOF(keycode);
1748 key = KEYOF(keycode);
1749
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);
1754 }
1755 #endif
1756
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);
1765 }
1766 return;
1767 }
1768
1769 shiftmask = k->k_shiftmask;
1770 if (newstate == RELEASED)
1771 shiftmask |= UPMASK;
1772
1773 km = settable(kbdd, shiftmask);
1774 if (km == NULL) { /* gross error */
1775 kbdcancelrpt(kbdd);
1776 return;
1777 }
1778
1779 if (key >= KEYMAP_SIZE)
1780 return;
1781 entry = km->keymap[key];
1782
1783 if (entry == NONL) {
1784 /*
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.
1789 */
1790 km = settable(kbdd, shiftmask & ~NUMLOCKMASK);
1791 if (km == NULL) { /* gross error */
1792 kbdcancelrpt(kbdd);
1793 return;
1794 }
1795 entry = km->keymap[key];
1796 }
1797 entrytype = (ushort_t)(entry & 0xFF00) >> 8;
1798
1799 if (entrytype == (SHIFTKEYS >> 8)) {
1800 /*
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.
1804 */
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 */
1810 }
1811 }
1812 } else {
1813 /*
1814 * Handle Compose and floating accent key sequences
1815 */
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;
1824 }
1825 }
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);
1848 }
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,
1866 q);
1867 }
1868 }
1869 }
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;
1883 }
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;
1893 }
1894 }
1895
1896 /*
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.
1899 *
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.
1903 */
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;
1914 }
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);
1919
1920 /*
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.
1924 */
1925 switch (entrytype) {
1926
1927 case 0x0: /* regular key */
1928 switch (kbdd->kbdd_translate) {
1929
1930 case TR_EVENT:
1931 fe.id = entry | k->k_buckybits;
1932 fe.value = 1;
1933 kbdkeypressed(kbdd, key, &fe, entry);
1934 break;
1935
1936 case TR_ASCII:
1937 kbdputcode(entry | k->k_buckybits, q);
1938 break;
1939 }
1940 break;
1941
1942 case SHIFTKEYS >> 8: {
1943 uint_t shiftbit = 1 << (entry & 0x0F);
1944
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);
1954 }
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);
1963 }
1964 k->k_togglemask |= shiftbit;
1965 }
1966 }
1967
1968 if (newstate == RELEASED)
1969 k->k_shiftmask &= ~shiftbit;
1970 else
1971 k->k_shiftmask |= shiftbit;
1972
1973 if (kbdd->kbdd_translate == TR_EVENT && newstate == PRESSED) {
1974 /*
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.
1979 */
1980 fe.id = SHIFT_CAPSLOCK + (entry & 0x0F);
1981 fe.value = 1;
1982 kbdkeypressed(kbdd, key, &fe, fe.id);
1983 }
1984 break;
1985 }
1986
1987 case BUCKYBITS >> 8:
1988 k->k_buckybits ^= 1 << (7 + (entry & 0x0F));
1989 if (kbdd->kbdd_translate == TR_EVENT && newstate == PRESSED) {
1990 /*
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.
1995 */
1996 fe.id = SHIFT_META + (entry & 0x0F);
1997 fe.value = 1;
1998 kbdkeypressed(kbdd, key, &fe, fe.id);
1999 }
2000 break;
2001
2002 case FUNNY >> 8:
2003 switch (entry) {
2004 case NOP:
2005 break;
2006
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;
2018
2019 case ERROR:
2020 cmn_err(CE_WARN, "kbd: Error detected");
2021 goto gotreset;
2022
2023 case COMPOSE:
2024 k->k_state = COMPOSE1;
2025 kbdd->led_state |= LED_COMPOSE;
2026 kbdsetled(kbdd);
2027 break;
2028 /*
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.
2033 */
2034 default:
2035 goto badentry;
2036 }
2037 break;
2038
2039 case FA_CLASS >> 8:
2040 if (k->k_state == NORMAL) {
2041 kbdd->fltaccent_entry = entry;
2042 k->k_state = FLTACCENT;
2043 }
2044 return;
2045
2046 case STRING >> 8:
2047 cp = &keystringtab[entry & 0x0F][0];
2048 while (*cp != '\0') {
2049 switch (kbdd->kbdd_translate) {
2050
2051 case TR_EVENT:
2052 kbd_send_esc_event(*cp, kbdd);
2053 break;
2054
2055 case TR_ASCII:
2056 kbdputcode((uchar_t)*cp, q);
2057 break;
2058 }
2059 cp++;
2060 }
2061 break;
2062
2063 case FUNCKEYS >> 8:
2064 switch (kbdd->kbdd_translate) {
2065
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;
2079
2080 case TR_EVENT:
2081 /*
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.
2088 */
2089 fe.id = (entry & 0x003F) + KEY_LEFTFIRST;
2090 fe.value = 1;
2091 /*
2092 * Assume "up" table only generates
2093 * shift changes.
2094 */
2095 kbdkeypressed(kbdd, key, &fe, fe.id);
2096 /*
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.
2104 */
2105 break;
2106 }
2107 break;
2108
2109 /*
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.
2114 */
2115 case PADKEYS >> 8:
2116 switch (kbdd->kbdd_translate) {
2117
2118 case TR_ASCII:
2119 kbdputcode(kb_numlock_table[entry&0x1F], q);
2120 break;
2121
2122 case TR_EVENT:
2123 /*
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.
2130 */
2131 fe.id = (entry & 0x001F) + VKEY_FIRSTPAD;
2132 fe.value = 1;
2133 /*
2134 * Assume "up" table only generates
2135 * shift changes.
2136 */
2137 kbdkeypressed(kbdd, key, &fe, fe.id);
2138 /*
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.
2146 */
2147 break;
2148 }
2149
2150 badentry:
2151 break;
2152 }
2153 }
2154
2155 static int
kbd_do_compose(ushort_t first_entry,ushort_t second_entry,ushort_t * result_iso_ptr)2156 kbd_do_compose(ushort_t first_entry, ushort_t second_entry,
2157 ushort_t *result_iso_ptr)
2158 {
2159 struct compose_sequence_t *ptr;
2160
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);
2166 }
2167 ptr++;
2168 }
2169 return (0);
2170 }
2171
2172 static void
kbd_send_esc_event(char c,register struct kbddata * kbdd)2173 kbd_send_esc_event(char c, register struct kbddata *kbdd)
2174 {
2175 Firm_event fe;
2176
2177 fe.id = c;
2178 fe.value = 1;
2179 fe.pair_type = FE_PAIR_NONE;
2180 fe.pair = 0;
2181 /*
2182 * Pretend as if each cp pushed and released
2183 * Calling kbdqueueevent avoids addr translation
2184 * and pair base determination of kbdkeypressed.
2185 */
2186 kbdqueueevent(kbdd, &fe);
2187 fe.value = 0;
2188 kbdqueueevent(kbdd, &fe);
2189 }
2190
2191 char *
strsetwithdecimal(char * buf,uint_t val,uint_t maxdigs)2192 strsetwithdecimal(char *buf, uint_t val, uint_t maxdigs)
2193 {
2194 int hradix = 5;
2195 char *bp;
2196 int lowbit;
2197 char *tab = "0123456789abcdef";
2198
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;
2206 }
2207 return (bp);
2208 }
2209
2210 static void
kbdkeypressed(struct kbddata * kbdd,uchar_t key_station,Firm_event * fe,ushort_t base)2211 kbdkeypressed(struct kbddata *kbdd, uchar_t key_station, Firm_event *fe,
2212 ushort_t base)
2213 {
2214 register struct keyboardstate *k;
2215 register short id_addr;
2216
2217 /* Set pair values */
2218 if (fe->id < (ushort_t)VKEY_FIRST) {
2219 /*
2220 * If CTRLed, find the ID that would have been used had it
2221 * not been CTRLed.
2222 */
2223 k = &kbdd->kbdd_state;
2224 if (k->k_shiftmask & (CTRLMASK | CTLSMASK)) {
2225 struct keymap *km;
2226
2227 km = settable(kbdd,
2228 k->k_shiftmask & ~(CTRLMASK | CTLSMASK | UPMASK));
2229 if (km == NULL)
2230 return;
2231 base = km->keymap[key_station];
2232 }
2233 if (base != fe->id) {
2234 fe->pair_type = FE_PAIR_SET;
2235 fe->pair = base;
2236 goto send;
2237 }
2238 }
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);
2255 }
2256 fe->id = vuid_id_offset(fe->id) | id_addr;
2257 kbdqueuepress(kbdd, key_station, fe);
2258 }
2259
2260 static void
kbdqueuepress(struct kbddata * kbdd,uchar_t key_station,Firm_event * fe)2261 kbdqueuepress(struct kbddata *kbdd, uchar_t key_station, Firm_event *fe)
2262 {
2263 register struct key_event *ke, *ke_free;
2264 register int i;
2265
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;
2284 }
2285 if (ke->key_station == 0)
2286 ke_free = ke;
2287 }
2288 if (ke_free) {
2289 ke = ke_free;
2290 goto add_event;
2291 }
2292 cmn_err(CE_WARN, "kbd: Too many keys down!");
2293 ke = kbdd->kbdd_downs;
2294 }
2295 add_event:
2296 ke->key_station = key_station;
2297 ke->event = *fe;
2298 kbdqueueevent(kbdd, fe);
2299 }
2300
2301 static void
kbdkeyreleased(register struct kbddata * kbdd,uchar_t key_station)2302 kbdkeyreleased(register struct kbddata *kbdd, uchar_t key_station)
2303 {
2304 register struct key_event *ke;
2305 register int i;
2306
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);
2325 }
2326 }
2327
2328 /*
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.
2332 */
2333 }
2334
2335 static void
kbdreleaseall(struct kbddata * kbdd)2336 kbdreleaseall(struct kbddata *kbdd)
2337 {
2338 register struct key_event *ke;
2339 register int i;
2340
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 */
2351 }
2352 }
2353
2354 /*
2355 * Pass a keycode up the stream, if you can, otherwise throw it away.
2356 */
2357 static void
kbdputcode(uint_t code,queue_t * q)2358 kbdputcode(uint_t code, queue_t *q)
2359 {
2360 register mblk_t *bp;
2361
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);
2371 }
2372 }
2373 }
2374
2375 /*
2376 * Pass generated keycode sequence to upstream, if possible.
2377 */
2378 static void
kbdputbuf(char * buf,queue_t * q)2379 kbdputbuf(char *buf, queue_t *q)
2380 {
2381 register mblk_t *bp;
2382
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++;
2393 }
2394 putnext(q, bp);
2395 }
2396 }
2397 }
2398
2399 /*
2400 * Pass a VUID "firm event" up the stream, if you can.
2401 */
2402 static void
kbdqueueevent(struct kbddata * kbdd,Firm_event * fe)2403 kbdqueueevent(struct kbddata *kbdd, Firm_event *fe)
2404 {
2405 register queue_t *q;
2406 register mblk_t *bp;
2407
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;
2423
2424 /*
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.
2429 *
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?
2433 */
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);
2442 }
2443 }
2444 }
2445