6324 Add an `ndp' tool for manipulating the neighbors table
[illumos-gate.git] / usr / src / uts / common / io / conskbd.c
blob53238205c2ecca023a9d9b40cc3a34b66e434a03
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
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
29 * Console kbd multiplexor driver for Sun.
30 * The console "zs" port is linked under us, with the "kbd" module pushed
31 * on top of it.
32 * Minor device 0 is what programs normally use.
33 * Minor device 1 is used to feed predigested keystrokes to the "workstation
34 * console" driver, which it is linked beneath.
37 * This module can support multiple keyboards to be used simultaneously.
38 * and enable users to use at a time multiple keyboards connected to the
39 * same system. All the keyboards are linked under conskbd, and act as a
40 * keyboard with replicated keys.
42 * The DIN keyboards of SUN, for exmple , type 3/4/5, are supported via
43 * a two-level architecure. The lower one is one of serialport drivers, such
44 * as zs, se, and the upper is "kb" STREAMS module. Currenly, the serialport
45 * drivers don't support polled I/O interfaces, we couldn't group the keyboard
46 * of this kind under conskbd. So we do as the follows:
48 * A new ioctl CONSSETKBDTYPE interface between conskbd and lower
49 * keyboard drivers is added. When conskbd receives I_LINK or I_PLINK
50 * ioctl, it will send a CONSSETKBDTYPE ioctl to the driver which is
51 * requesting to be linked under conskbd. If the lower driver does't
52 * recognize this ioctl, the virtual keyboard will be disabled so that
53 * only one keyboard instance could be linked under conskbd.
55 #define KEYMAP_SIZE_VARIABLE
57 #include <sys/types.h>
58 #include <sys/param.h>
59 #include <sys/stropts.h>
60 #include <sys/stream.h>
61 #include <sys/strsubr.h>
62 #include <sys/strsun.h>
63 #include <sys/conf.h>
64 #include <sys/stat.h>
65 #include <sys/errno.h>
66 #include <sys/modctl.h>
67 #include <sys/kbio.h>
68 #include <sys/ddi.h>
69 #include <sys/sunddi.h>
70 #include <sys/consdev.h>
71 #include <sys/note.h>
72 #include <sys/kmem.h>
73 #include <sys/kstat.h>
74 #include <sys/policy.h>
75 #include <sys/kbd.h>
76 #include <sys/kbtrans.h>
77 #include <sys/promif.h>
78 #include <sys/vuid_event.h>
79 #include <sys/conskbd.h>
80 #include <sys/beep.h>
82 extern struct keyboard *kbtrans_usbkb_maptab_init(void);
83 extern void kbtrans_usbkb_maptab_fini(struct keyboard **);
84 extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t);
87 * Module linkage routines for the kernel
89 static int conskbd_attach(dev_info_t *, ddi_attach_cmd_t);
90 static int conskbd_detach(dev_info_t *, ddi_detach_cmd_t);
91 static int conskbd_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
94 * STREAMS queue processing procedures
96 static void conskbduwsrv(queue_t *);
97 static void conskbdlwserv(queue_t *);
98 static void conskbdlrput(queue_t *, mblk_t *);
99 static int conskbdclose(queue_t *, int, cred_t *);
100 static int conskbdopen(queue_t *, dev_t *, int, int, cred_t *);
103 /* STREAMS driver id and limit value struct */
104 static struct module_info conskbdm_info = {
105 0, /* mi_idnum */
106 "conskbd", /* mi_idname */
107 0, /* mi_minpsz */
108 1024, /* mi_maxpsz */
109 2048, /* mi_hiwat */
110 128 /* mi_lowat */
114 * STREAMS queue processing procedure structures
116 /* upper read queue processing procedure structures */
117 static struct qinit conskbdurinit = {
118 NULL, /* qi_putp */
119 (int (*)())NULL, /* qi_srvp */
120 conskbdopen, /* qi_qopen */
121 conskbdclose, /* qi_qclose */
122 (int (*)())NULL, /* qi_qadmin */
123 &conskbdm_info, /* qi_minfo */
124 NULL /* qi_mstat */
127 /* upper write queue processing procedures structuresi */
128 static struct qinit conskbduwinit = {
129 (int (*)())putq, /* qi_putp */
130 (int (*)())conskbduwsrv, /* qi_srvp */
131 conskbdopen, /* qi_qopen */
132 conskbdclose, /* qi_qclose */
133 (int (*)())NULL, /* qi_qadmin */
134 &conskbdm_info, /* qi_minfo */
135 NULL /* qi_mstat */
138 /* lower read queue processing procedures structures */
139 static struct qinit conskbdlrinit = {
140 (int (*)())conskbdlrput, /* qi_putp */
141 (int (*)())NULL, /* qi_srvp */
142 (int (*)())NULL, /* qi_qopen */
143 (int (*)())NULL, /* qi_qclose */
144 (int (*)())NULL, /* qi_qadmin */
145 &conskbdm_info, /* qi_minfo */
146 NULL /* qi_mstat */
149 /* lower write processing procedures structures */
150 static struct qinit conskbdlwinit = {
151 putq, /* qi_putp */
152 (int (*)())conskbdlwserv, /* qi_srvp */
153 (int (*)())NULL, /* qi_qopen */
154 (int (*)())NULL, /* qi_qclose */
155 (int (*)())NULL, /* qi_qadmin */
156 &conskbdm_info, /* qi_minfo */
157 NULL /* qi_mstat */
160 /* STREAMS entity declaration structure */
161 static struct streamtab conskbd_str_info = {
162 &conskbdurinit, /* st_rdinit */
163 &conskbduwinit, /* st_wrinit */
164 &conskbdlrinit, /* st_muxrinit */
165 &conskbdlwinit, /* st_muxwinit */
169 /* Entry points structure */
170 static struct cb_ops cb_conskbd_ops = {
171 nulldev, /* cb_open */
172 nulldev, /* cb_close */
173 nodev, /* cb_strategy */
174 nodev, /* cb_print */
175 nodev, /* cb_dump */
176 nodev, /* cb_read */
177 nodev, /* cb_write */
178 nodev, /* cb_ioctl */
179 nodev, /* cb_devmap */
180 nodev, /* cb_mmap */
181 nodev, /* cb_segmap */
182 nochpoll, /* cb_chpoll */
183 ddi_prop_op, /* cb_prop_op */
184 &conskbd_str_info, /* cb_stream */
185 D_MP | D_MTOUTPERIM | D_MTOCEXCL /* cb_flag */
190 * Device operations structure
192 static struct dev_ops conskbd_ops = {
193 DEVO_REV, /* devo_rev */
194 0, /* devo_refcnt */
195 conskbd_info, /* devo_getinfo */
196 nulldev, /* devo_identify */
197 nulldev, /* devo_probe */
198 conskbd_attach, /* devo_attach */
199 conskbd_detach, /* devo_detach */
200 nodev, /* devo_reset */
201 &(cb_conskbd_ops), /* devo_cb_ops */
202 (struct bus_ops *)NULL, /* devo_bus_ops */
203 NULL, /* devo_power */
204 ddi_quiesce_not_needed, /* quiesce */
208 * Module linkage information for the kernel.
210 static struct modldrv modldrv = {
211 &mod_driverops, /* Type of module. This one is a pseudo driver */
212 "conskbd multiplexer driver",
213 &conskbd_ops, /* driver ops */
217 * Module linkage structure
219 static struct modlinkage modlinkage = {
220 MODREV_1, /* ml_rev */
221 &modldrv, /* ml_linkage */
222 NULL /* NULL terminates the list */
226 * Debug printing
228 #ifndef DPRINTF
229 #ifdef DEBUG
230 void conskbd_dprintf(const char *fmt, ...);
231 #define DPRINTF(l, m, args) \
232 (((l) >= conskbd_errlevel) && ((m) & conskbd_errmask) ? \
233 conskbd_dprintf args : \
234 (void) 0)
237 * Severity levels for printing
239 #define PRINT_L0 0 /* print every message */
240 #define PRINT_L1 1 /* debug */
241 #define PRINT_L2 2 /* quiet */
244 * Masks
246 #define PRINT_MASK_ALL 0xFFFFFFFFU
247 uint_t conskbd_errmask = PRINT_MASK_ALL;
248 uint_t conskbd_errlevel = PRINT_L2;
250 #else
251 #define DPRINTF(l, m, args) /* NOTHING */
252 #endif
253 #endif
256 * Module global data are protected by outer perimeter. Modifying
257 * these global data is executed in outer perimeter exclusively.
258 * Except in conskbdopen() and conskbdclose(), which are entered
259 * exclusively (Refer to D_MTOCEXCL flag), all changes for the
260 * global variables are protected by qwriter().
262 static queue_t *conskbd_regqueue; /* regular keyboard queue above us */
263 static queue_t *conskbd_consqueue; /* console queue above us */
266 static dev_info_t *conskbd_dip; /* private copy of devinfo pointer */
267 static long conskbd_idle_stamp; /* seconds tstamp of latest keystroke */
268 static struct keyboard *conskbd_keyindex;
271 * Normally, kstats of type KSTAT_TYPE_NAMED have multiple elements. In
272 * this case we use this type for a single element because the ioctl code
273 * for it knows how to handle mixed kernel/user data models. Also, it
274 * will be easier to add new statistics later.
276 static struct {
277 kstat_named_t idle_sec; /* seconds since last keystroke */
278 } conskbd_kstat = {
279 { "idle_sec", KSTAT_DATA_LONG, }
283 * Local routines prototypes
285 static int conskbd_kstat_update(kstat_t *, int);
287 static void conskbd_ioctl(queue_t *, mblk_t *);
288 static void conskbd_ioc_plink(queue_t *, mblk_t *);
289 static void conskbd_ioc_punlink(queue_t *, mblk_t *);
290 static void conskbd_legacy_kbd_ioctl(queue_t *, mblk_t *);
291 static void conskbd_virtual_kbd_ioctl(queue_t *, mblk_t *);
292 static mblk_t *conskbd_alloc_firm_event(ushort_t, int);
294 static conskbd_pending_msg_t *conskbd_mux_find_msg(mblk_t *);
295 static void conskbd_mux_enqueue_msg(conskbd_pending_msg_t *);
296 static void conskbd_mux_dequeue_msg(conskbd_pending_msg_t *);
297 static void conskbd_link_lowque_virt(queue_t *, mblk_t *);
298 static void conskbd_link_lowque_legacy(queue_t *, mblk_t *);
300 static void conskbd_handle_downstream_msg(queue_t *, mblk_t *);
301 static void conskbd_kioctype_complete(conskbd_lower_queue_t *, mblk_t *);
302 static void conskbd_kioctrans_complete(conskbd_lower_queue_t *, mblk_t *);
303 static void conskbd_kioclayout_complete(conskbd_lower_queue_t *, mblk_t *);
304 static void conskbd_kiocsled_complete(conskbd_lower_queue_t *, mblk_t *);
305 static void conskbd_mux_upstream_msg(conskbd_lower_queue_t *, mblk_t *);
306 static void conskbd_legacy_upstream_msg(conskbd_lower_queue_t *, mblk_t *);
307 static void conskbd_lqs_ack_complete(conskbd_lower_queue_t *, mblk_t *);
309 static void conskbd_polledio_enter(cons_polledio_arg_t);
310 static void conskbd_polledio_exit(cons_polledio_arg_t);
311 static int conskbd_polledio_ischar(cons_polledio_arg_t);
312 static int conskbd_polledio_getchar(cons_polledio_arg_t);
313 static void conskbd_polledio_setled(struct kbtrans_hardware *, int);
315 static void conskbd_streams_setled(struct kbtrans_hardware *, int);
316 static boolean_t conskbd_override_kbtrans(queue_t *, mblk_t *);
317 static boolean_t
318 conskbd_polled_keycheck(struct kbtrans_hardware *,
319 kbtrans_key_t *, enum keystate *);
322 * Callbacks needed by kbtrans
324 static struct kbtrans_callbacks conskbd_callbacks = {
325 conskbd_streams_setled,
326 conskbd_polledio_setled,
327 conskbd_polled_keycheck,
331 * Single private "global" lock for the few rare conditions
332 * we want single-threaded.
334 static kmutex_t conskbd_msgq_lock;
335 static conskbd_pending_msg_t *conskbd_msg_queue;
338 * The software state structure of virtual keyboard.
339 * Currently, only one virtual keyboard is supported.
341 static conskbd_state_t conskbd = { 0 };
343 /* This variable backs up the layout state for non-self-ID keyboards */
344 static int kbd_layout_bak = 0;
347 * _init()
349 * Description:
350 * Driver initialization, called when driver is first loaded.
351 * This is how access is initially given to all the static structures.
353 * Arguments:
354 * None
356 * Returns:
357 * ddi_soft_state_init() status, see ddi_soft_state_init(9f), or
358 * mod_install() status, see mod_install(9f)
361 _init(void)
363 int error;
365 error = mod_install(&modlinkage);
366 if (error != 0) {
367 return (error);
370 conskbd_keyindex = kbtrans_usbkb_maptab_init();
372 mutex_init(&conskbd_msgq_lock, NULL, MUTEX_DRIVER, NULL);
374 return (error);
376 } /* _init() */
379 * _fini()
381 * Description:
382 * Module de-initialization, called when the driver is to be unloaded.
384 * Arguments:
385 * None
387 * Returns:
388 * mod_remove() status, see mod_remove(9f)
391 _fini(void)
393 int error;
395 error = mod_remove(&modlinkage);
396 if (error != 0)
397 return (error);
398 mutex_destroy(&conskbd_msgq_lock);
399 kbtrans_usbkb_maptab_fini(&conskbd_keyindex);
401 return (0);
403 } /* _fini() */
406 * _info()
408 * Description:
409 * Module information, returns information about the driver.
411 * Arguments:
412 * modinfo *modinfop Pointer to the opaque modinfo structure
414 * Returns:
415 * mod_info() status, see mod_info(9f)
418 _info(struct modinfo *modinfop)
420 return (mod_info(&modlinkage, modinfop));
422 } /* _info() */
426 * conskbd_attach()
428 * Description:
429 * This routine creates two device nodes. One is the "kbd" node, which
430 * is used by user application programs(such as Xserver).The other is the
431 * "conskbd" node, which is an internal node. consconfig_dacf module will
432 * open this internal node, and link the conskbd under the wc (workstaion
433 * console).
435 * Arguments:
436 * dev_info_t *dip Pointer to the device's dev_info struct
437 * ddi_attach_cmd_t cmd Attach command
439 * Returns:
440 * DDI_SUCCESS The driver was initialized properly
441 * DDI_FAILURE The driver couldn't be initialized properly
443 /*ARGSUSED*/
444 static int
445 conskbd_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
447 kstat_t *ksp;
449 switch (cmd) {
450 case DDI_ATTACH:
451 break;
453 default:
454 return (DDI_FAILURE);
457 if ((ddi_create_minor_node(devi, "kbd", S_IFCHR,
458 0, DDI_PSEUDO, NULL) == DDI_FAILURE) ||
459 (ddi_create_internal_pathname(devi, "conskbd", S_IFCHR,
460 1) == DDI_FAILURE)) {
461 ddi_remove_minor_node(devi, NULL);
462 return (DDI_FAILURE);
464 conskbd_dip = devi;
466 ksp = kstat_create("conskbd", 0, "activity", "misc", KSTAT_TYPE_NAMED,
467 sizeof (conskbd_kstat) / sizeof (kstat_named_t),
468 KSTAT_FLAG_VIRTUAL);
469 if (ksp) {
470 ksp->ks_data = (void *) &conskbd_kstat;
471 ksp->ks_update = conskbd_kstat_update;
472 kstat_install(ksp);
473 conskbd_idle_stamp = gethrestime_sec(); /* initial value */
476 conskbd.conskbd_layout = -1; /* invalid layout */
477 conskbd.conskbd_led_state = -1;
478 conskbd.conskbd_bypassed = B_FALSE;
480 return (DDI_SUCCESS);
482 } /* conskbd_attach() */
485 * conskbd_detach()
487 * Description:
488 * Detach an instance of the conskbd driver. In fact, the driver can not
489 * be detached.
491 * Arguments:
492 * dev_info_t *dip Pointer to the device's dev_info struct
493 * ddi_detach_cmd_t cmd Detach command
495 * Returns:
496 * DDI_SUCCESS The driver was detached
497 * DDI_FAILURE The driver couldn't be detached
499 /*ARGSUSED*/
500 static int
501 conskbd_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
503 return (DDI_FAILURE);
505 } /* conskbd_detach() */
507 /* ARGSUSED */
508 static int
509 conskbd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
510 void **result)
512 register int error;
514 switch (infocmd) {
515 case DDI_INFO_DEVT2DEVINFO:
516 if (conskbd_dip == NULL) {
517 error = DDI_FAILURE;
518 } else {
519 *result = (void *) conskbd_dip;
520 error = DDI_SUCCESS;
522 break;
523 case DDI_INFO_DEVT2INSTANCE:
524 *result = (void *)0;
525 error = DDI_SUCCESS;
526 break;
527 default:
528 error = DDI_FAILURE;
530 return (error);
532 } /* conskbd_info() */
534 /*ARGSUSED*/
535 static int
536 conskbdopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
538 dev_t unit;
539 int err;
541 unit = getminor(*devp);
543 if (unit == 0) {
545 * Opening "/dev/kbd".
547 conskbd_regqueue = q;
548 qprocson(q);
549 return (0);
550 } else if (unit != 1) {
551 /* we don't do that under Bozo's Big Tent */
552 return (ENODEV);
556 * Check if already initialized
558 if (conskbd_consqueue != NULL)
559 return (0);
562 * Opening the device to be linked under the console.
564 conskbd_consqueue = q;
566 if (secpolicy_console(crp) != 0)
567 return (EPERM);
570 * initialize kbtrans module for conskbd
572 err = kbtrans_streams_init(q, sflag, (struct kbtrans_hardware *)
573 &conskbd, &conskbd_callbacks, &conskbd.conskbd_kbtrans, 0, 0);
574 if (err != 0)
575 return (err);
576 kbtrans_streams_set_keyboard(conskbd.conskbd_kbtrans, KB_USB,
577 conskbd_keyindex);
579 conskbd.conskbd_polledio.cons_polledio_version = CONSPOLLEDIO_V1;
580 conskbd.conskbd_polledio.cons_polledio_argument =
581 (cons_polledio_arg_t)&conskbd;
582 conskbd.conskbd_polledio.cons_polledio_putchar = NULL;
583 conskbd.conskbd_polledio.cons_polledio_getchar =
584 (int (*)(cons_polledio_arg_t)) conskbd_polledio_getchar;
585 conskbd.conskbd_polledio.cons_polledio_ischar =
586 (boolean_t (*)(cons_polledio_arg_t))conskbd_polledio_ischar;
587 conskbd.conskbd_polledio.cons_polledio_enter = conskbd_polledio_enter;
588 conskbd.conskbd_polledio.cons_polledio_exit = conskbd_polledio_exit;
589 qprocson(q);
591 return (0);
593 } /* conskbdopen() */
596 /*ARGSUSED*/
597 static int
598 conskbdclose(queue_t *q, int flag, cred_t *crp)
600 if (q == conskbd_regqueue) {
602 conskbd_pending_msg_t *pmsg, *prev, *next;
603 mblk_t *mp;
605 /* switch the input stream back to conskbd_consqueue */
606 conskbd.conskbd_directio = B_FALSE;
608 kbtrans_streams_untimeout(conskbd.conskbd_kbtrans);
609 kbtrans_streams_set_queue(conskbd.conskbd_kbtrans,
610 conskbd_consqueue);
611 qprocsoff(q);
612 conskbd_regqueue = NULL;
615 * If there are any pending ioctls which conskbd hasn't
616 * responded to yet, remove them from conskbd_msg_queue.
617 * Otherwise, we might send the response to a nonexistent
618 * closed queue. Refer to: conskbd_mux_upstream_msg().
620 for (prev = NULL, pmsg = conskbd_msg_queue; pmsg != NULL;
621 pmsg = next) {
622 next = pmsg->kpm_next;
623 if (pmsg->kpm_upper_queue == WR(q)) {
624 if (prev == NULL)
625 conskbd_msg_queue = next;
626 else
627 prev->kpm_next = next;
629 while (pmsg->kpm_resp_list != NULL) {
630 mp = pmsg->kpm_resp_list;
631 pmsg->kpm_resp_list = mp->b_next;
632 mp->b_next = mp->b_prev = NULL;
633 freemsg(mp);
635 mutex_destroy(&pmsg->kpm_lock);
636 kmem_free(pmsg, sizeof (*pmsg));
637 } else {
638 prev = pmsg;
641 } else if (q == conskbd_consqueue) {
643 * Well, this is probably a mistake, but we will permit you
644 * to close the path to the console if you really insist.
646 qprocsoff(q);
647 conskbd_consqueue = NULL;
650 return (0);
652 } /* conskbdclose() */
655 * Service procedure for upper write queue.
656 * To make sure the order of messages, we don't process any
657 * message in qi_putq() routine of upper write queue, instead the
658 * qi_putq() routine, which is a standard putq() routine, puts all
659 * messages into a queue, and lets the following service procedure
660 * deal with all messages.
661 * This routine is invoked when ioctl commands are send down
662 * by a consumer of the keyboard device, eg, when the keyboard
663 * consumer tries to determine the keyboard layout type, or sets
664 * the led states.
666 static void
667 conskbduwsrv(queue_t *q)
669 mblk_t *mp;
670 queue_t *oldq;
671 enum kbtrans_message_response ret;
672 struct copyresp *csp;
673 struct freq_request *frqp;
674 int error;
676 while ((mp = getq(q)) != NULL) {
679 * if the virtual keyboard is supported
681 if (conskbd.conskbd_bypassed == B_FALSE) {
683 if (conskbd_override_kbtrans(q, mp) == B_TRUE)
684 continue;
686 * The conskbd driver is a psaudo driver. It has two
687 * devcice nodes, one is used by kernel, and the other
688 * is used by end-users. There are two STREAMS queues
689 * corresponding to the two device nodes, console queue
690 * and regular queue.
691 * In conskbd_override_kbtrans() routine, when receives
692 * KIOCSDIRECT ioctl, we need change the direction of
693 * keyboard input messages, and direct the input stream
694 * from keyboard into right queue. It causes this queue
695 * to be switched between regular queue and console
696 * queue. And here, in this routine, the in-parameter
697 * "q" can be any one of the two. Moreover, this module
698 * is executed in multithreaded environment, even if the
699 * q is switched to regular queue, it is possible that
700 * the in-parameter is still the console queue, and we
701 * need to return response to right queue.
702 * The response is sent to upstream by the kbtrans
703 * module. so we need to save the old queue, and wait
704 * kbtrans to proces message and to send response out,
705 * and then switch back to old queue.
707 oldq = kbtrans_streams_get_queue(
708 conskbd.conskbd_kbtrans);
709 kbtrans_streams_set_queue(
710 conskbd.conskbd_kbtrans, RD(q));
711 ret = kbtrans_streams_message(
712 conskbd.conskbd_kbtrans, mp);
713 kbtrans_streams_set_queue(
714 conskbd.conskbd_kbtrans, oldq);
716 switch (ret) {
717 case KBTRANS_MESSAGE_HANDLED:
718 continue;
719 case KBTRANS_MESSAGE_NOT_HANDLED:
720 break;
724 switch (mp->b_datap->db_type) {
726 case M_IOCTL:
727 conskbd_ioctl(q, mp);
728 break;
730 case M_FLUSH:
731 if (*mp->b_rptr & FLUSHW) {
732 flushq(q, FLUSHDATA);
735 * here, if flush read queue, some key-up messages
736 * may be lost so that upper module or applications
737 * treat corresponding keys as being held down for
738 * ever.
740 freemsg(mp);
741 break;
743 case M_DATA:
745 * virtual keyboard doesn't support this interface.
746 * only when it is disabled, we pass the message
747 * down to lower queue.
749 if ((conskbd.conskbd_bypassed) &&
750 (conskbd.conskbd_lqueue_nums > 0)) {
751 if (putq(conskbd.conskbd_lqueue_list->
752 lqs_queue, mp) != 1)
753 freemsg(mp);
754 } else {
755 freemsg(mp);
757 break;
759 case M_IOCDATA:
761 * Only deal with copyresp to KIOCSETFREQ
762 * transparent ioctl now
764 csp = (struct copyresp *)mp->b_rptr;
765 if (csp->cp_rval) {
766 miocnak(q, mp, 0, EINVAL);
767 break;
770 error = 0;
771 switch (csp->cp_cmd) {
772 case KIOCSETFREQ:
773 frqp = (struct freq_request *)mp->
774 b_cont->b_rptr;
776 switch (frqp->type) {
777 case CONSOLE_BEEP:
778 error = beeper_freq(BEEP_CONSOLE,
779 (int)frqp->freq);
780 break;
782 case KBD_BEEP:
783 error = beeper_freq(BEEP_TYPE4,
784 (int)frqp->freq);
785 break;
787 default:
788 error = 1;
789 } /* frqp->type */
791 break;
793 default:
794 error = 1;
795 } /* csp->cp_cmd */
797 if (error == 0)
798 miocack(q, mp, 0, 0);
799 else
800 miocnak(q, mp, 0, EINVAL);
802 break;
804 default:
806 * Pass an error message up.
808 mp->b_datap->db_type = M_ERROR;
809 if (mp->b_cont) {
810 freemsg(mp->b_cont);
811 mp->b_cont = NULL;
813 mp->b_rptr = mp->b_datap->db_base;
814 mp->b_wptr = mp->b_rptr + sizeof (char);
815 *mp->b_rptr = EINVAL;
816 qreply(q, mp);
818 } /* end of while */
820 } /* conskbduwsrv() */
822 static void
823 conskbd_ioctl(queue_t *q, mblk_t *mp)
825 struct iocblk *iocp;
826 int error = 0;
828 iocp = (struct iocblk *)mp->b_rptr;
830 switch (iocp->ioc_cmd) {
832 case I_LINK:
833 case I_PLINK:
834 if (conskbd.conskbd_bypassed == B_TRUE) {
836 * A legacy keyboard can NOT be connected to conskbd together
837 * with other keyboards. So when a legacy keyboard is already
838 * linked under conkbd, we just reject all others.
840 miocnak(q, mp, 0, EAGAIN);
841 break;
843 qwriter(q, mp, conskbd_ioc_plink, PERIM_OUTER);
844 break;
846 case I_UNLINK:
847 case I_PUNLINK:
848 qwriter(q, mp, conskbd_ioc_punlink, PERIM_OUTER);
849 break;
851 case KIOCSKABORTEN:
853 * Check if privileged
855 if ((error = secpolicy_sys_config(iocp->ioc_cr, B_FALSE))) {
856 miocnak(q, mp, 0, error);
857 return;
860 error = miocpullup(mp, sizeof (int));
861 if (error != 0) {
862 miocnak(q, mp, 0, error);
863 return;
866 abort_enable = *(int *)mp->b_cont->b_rptr;
867 miocack(q, mp, 0, 0);
868 break;
870 case KIOCSETFREQ:
871 if (iocp->ioc_count != TRANSPARENT) {
873 * We don't support non-transparent ioctls,
874 * i.e. I_STR ioctls
876 miocnak(q, mp, 0, EINVAL);
877 } else {
878 /* Transparent ioctl */
879 mcopyin(mp, NULL, sizeof (struct freq_request), NULL);
880 qreply(q, mp);
882 break;
884 default:
885 if (conskbd.conskbd_bypassed == B_TRUE) {
886 conskbd_legacy_kbd_ioctl(q, mp);
887 } else {
888 conskbd_virtual_kbd_ioctl(q, mp);
892 } /* conskbd_ioctl() */
895 static void
896 conskbd_virtual_kbd_ioctl(queue_t *q, mblk_t *mp)
898 struct iocblk *iocp;
899 mblk_t *datap;
900 int cmd;
901 int error = 0;
903 iocp = (struct iocblk *)mp->b_rptr;
905 switch (iocp->ioc_cmd) {
906 case KIOCLAYOUT:
907 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
908 miocnak(q, mp, 0, ENOMEM);
909 break;
912 if (conskbd.conskbd_layout == -1)
913 *(int *)datap->b_wptr = KBTRANS_USBKB_DEFAULT_LAYOUT;
914 else
915 *(int *)datap->b_wptr = conskbd.conskbd_layout;
917 datap->b_wptr += sizeof (int);
918 if (mp->b_cont)
919 freemsg(mp->b_cont);
920 mp->b_cont = datap;
921 miocack(q, mp, sizeof (int), 0);
922 break;
924 case KIOCSLAYOUT:
925 if (iocp->ioc_count != TRANSPARENT) {
926 miocnak(q, mp, 0, EINVAL);
927 break;
929 kbd_layout_bak = conskbd.conskbd_layout;
930 conskbd.conskbd_layout = *(intptr_t *)(mp->b_cont->b_rptr);
931 if (conskbd.conskbd_layout != kbd_layout_bak) {
933 /* notify the upper of the change event */
934 if ((datap = conskbd_alloc_firm_event(
935 KEYBOARD_LAYOUT_CHANGE,
936 conskbd.conskbd_layout)) != NULL) {
937 if (conskbd.conskbd_directio) {
938 putnext(conskbd_regqueue, datap);
939 } else {
940 freemsg(datap);
944 miocack(q, mp, 0, 0);
945 break;
947 case CONSOPENPOLLEDIO:
948 error = miocpullup(mp, sizeof (struct cons_polledio *));
949 if (error != 0) {
950 miocnak(q, mp, 0, error);
951 break;
953 if (conskbd.conskbd_lqueue_list == NULL) {
954 miocnak(q, mp, 0, EINVAL);
955 break;
957 conskbd_handle_downstream_msg(q, mp);
958 break;
960 case CONSCLOSEPOLLEDIO:
961 if (conskbd.conskbd_lqueue_list == NULL) {
962 miocnak(q, mp, 0, EINVAL);
963 break;
965 conskbd_handle_downstream_msg(q, mp);
966 break;
968 case CONSSETABORTENABLE:
970 * To enable combined STOP-A(or F1-A) to trap into kmdb,
971 * the lower physical keyboard drivers are always told not
972 * to parse abort sequence(refer to consconfig_dacf module).
973 * Instead, lower drivers always send all keydown & keyup
974 * messages up to conskbd, so that when key STOP(or F1) is
975 * pressed on one keyboard and key A is pressed on another
976 * keyboard, the system could trap into kmdb.
978 * When we by kbtrans_streams_message() invoked kbtrans to
979 * handle ioctls in conskbduwsrv() routine, kbtrans module
980 * already handle the message though it returned to us a
981 * KBTRANS_MESSAGE_NOT_HANDLED. For virtual keyboard, no
982 * special initialization or un-initialization is needed.
983 * So we just return ACK to upper module.
985 miocack(q, mp, 0, 0);
986 break;
988 case KIOCCMD:
989 case KIOCMKTONE:
990 if (conskbd.conskbd_lqueue_list == NULL ||
991 mp->b_cont == NULL) {
992 miocnak(q, mp, 0, EINVAL);
993 break;
995 cmd = *(int *)mp->b_cont->b_rptr;
996 if (cmd == KBD_CMD_GETLAYOUT) {
997 freemsg(mp->b_cont);
998 datap = allocb(sizeof (int), BPRI_HI);
999 if (datap == NULL) {
1000 miocnak(q, mp, 0, ENOMEM);
1001 return;
1003 if (conskbd.conskbd_layout == -1)
1004 *(int *)datap->b_wptr =
1005 KBTRANS_USBKB_DEFAULT_LAYOUT;
1006 else
1007 *(int *)datap->b_wptr = conskbd.conskbd_layout;
1009 mp->b_cont = datap;
1010 miocack(q, mp, sizeof (int), 0);
1011 return;
1013 conskbd_handle_downstream_msg(q, mp);
1014 break;
1016 default:
1017 miocnak(q, mp, 0, EINVAL);
1018 break;
1021 } /* conskbd_virtual_kbd_ioctl() */
1023 static void
1024 conskbd_legacy_kbd_ioctl(queue_t *q, mblk_t *mp)
1026 conskbd_lower_queue_t *lq;
1027 struct iocblk *iocp;
1028 int error = 0;
1030 iocp = (struct iocblk *)mp->b_rptr;
1032 ASSERT(conskbd.conskbd_lqueue_nums == 1);
1033 switch (iocp->ioc_cmd) {
1035 case KIOCGDIRECT: {
1036 mblk_t *datap;
1038 if ((datap = allocb(sizeof (int), BPRI_MED)) == NULL) {
1039 miocnak(q, mp, 0, ENOMEM);
1040 break;
1043 *(int *)datap->b_wptr = conskbd.conskbd_directio;
1044 datap->b_wptr += sizeof (int);
1045 if (mp->b_cont != NULL) {
1046 freemsg(mp->b_cont);
1047 mp->b_cont = NULL;
1049 mp->b_cont = datap;
1050 miocack(q, mp, sizeof (int), 0);
1051 break;
1054 case KIOCSDIRECT:
1055 error = miocpullup(mp, sizeof (int));
1056 if (error != 0) {
1057 miocnak(q, mp, 0, error);
1058 break;
1060 conskbd.conskbd_directio = *(int *)mp->b_cont->b_rptr;
1063 * Pass this through, if there's something to pass
1064 * it through to, so the system keyboard can reset
1065 * itself.
1067 if (conskbd.conskbd_lqueue_nums > 0) {
1068 lq = conskbd.conskbd_lqueue_list;
1069 ASSERT(lq && lq->lqs_next == NULL);
1070 if (putq(lq->lqs_queue, mp) != 1) {
1071 miocnak(q, mp, 0, ENOMEM);
1072 return;
1074 break;
1077 miocack(q, mp, 0, 0);
1078 break;
1080 default:
1082 * Pass this through, if there's something to pass it
1083 * through to; otherwise, reject it.
1085 if (conskbd.conskbd_lqueue_nums > 0) {
1086 lq = conskbd.conskbd_lqueue_list;
1087 ASSERT(lq && lq->lqs_next == NULL);
1088 if (putq(lq->lqs_queue, mp) != 1) {
1089 miocnak(q, mp, 0, ENOMEM);
1090 return;
1092 break;
1095 /* nobody below us; reject it */
1096 miocnak(q, mp, 0, EINVAL);
1097 break;
1100 } /* conskbd_legacy_kbd_ioctl() */
1104 * Service procedure for lower write queue.
1105 * Puts things on the queue below us, if it lets us.
1107 static void
1108 conskbdlwserv(queue_t *q)
1110 register mblk_t *mp;
1112 while (canput(q->q_next) && (mp = getq(q)) != NULL)
1113 putnext(q, mp);
1115 } /* conskbdlwserv() */
1118 * Put procedure for lower read queue.
1119 * Pass everything up to minor device 0 if "directio" set, otherwise to minor
1120 * device 1.
1122 static void
1123 conskbdlrput(queue_t *q, mblk_t *mp)
1125 conskbd_lower_queue_t *lqs;
1126 struct iocblk *iocp;
1127 Firm_event *fe;
1129 DPRINTF(PRINT_L1, PRINT_MASK_ALL, ("conskbdlrput\n"));
1131 switch (mp->b_datap->db_type) {
1133 case M_FLUSH:
1134 if (*mp->b_rptr == FLUSHR) {
1135 flushq(q, FLUSHDATA); /* XXX doesn't flush M_DELAY */
1136 *mp->b_rptr &= ~FLUSHR; /* it has been flushed */
1138 if (*mp->b_rptr == FLUSHW) {
1139 flushq(WR(q), FLUSHDATA);
1140 qreply(q, mp); /* give the read queues a crack at it */
1141 } else
1142 freemsg(mp);
1143 break;
1145 case M_DATA:
1146 if (conskbd.conskbd_bypassed == B_FALSE) {
1148 fe = (Firm_event *)mp->b_rptr;
1151 * This is a workaround.
1153 * According to HID specification, there are the
1154 * following keycode mapping between PS2 and USB,
1156 * PS2 AT-101 keycode(29) ---> USB(49)
1157 * PS2 AT-102 keycode(42) ---> USB(50)
1159 * However, the two keys, AT-101(29) and AT-102(42),
1160 * have the same scancode,0x2B, in PS2 scancode SET1
1161 * which we are using. The Kb8042 driver always
1162 * recognizes the two keys as PS2(29) so that we could
1163 * not know which is being pressed or released when we
1164 * receive scancode 0x2B. Fortunately, the two keys can
1165 * not co-exist in a specific layout. In other words,
1166 * in the table of keycode-to-symbol mapping, either
1167 * entry 49 or 50 is a hole. So, if we're processing a
1168 * keycode 49, we look at the entry for 49. If it's
1169 * HOLE, remap the key to 50; If we're processing a 50,
1170 * look at the entry for 50. If it's HOLE, we remap
1171 * the key to 49.
1173 if (fe->id == 49 || fe->id == 50) {
1174 if (conskbd_keyindex->k_normal[50] == HOLE)
1175 fe->id = 49;
1176 else
1177 fe->id = 50;
1181 * Remember key state of each key of lower physical
1182 * keyboard. When a keyboard is umplumbed from conskbd,
1183 * we will check all key states. By then, we will fake
1184 * a KEY_RELEASED message for each key in KEY_PRESSED
1185 * state. Otherwise, upper module will treat these keys
1186 * as held-down for ever.
1188 iocp = (struct iocblk *)mp->b_rptr;
1189 lqs = (conskbd_lower_queue_t *)q->q_ptr;
1190 if (fe->value)
1191 lqs->lqs_key_state[fe->id] = KEY_PRESSED;
1192 else
1193 lqs->lqs_key_state[fe->id] = KEY_RELEASED;
1195 kbtrans_streams_key(conskbd.conskbd_kbtrans,
1196 fe->id, fe->value ? KEY_PRESSED : KEY_RELEASED);
1197 freemsg(mp);
1198 } else {
1199 if (conskbd.conskbd_directio)
1200 putnext(conskbd_regqueue, mp);
1201 else if (conskbd_consqueue != NULL)
1202 putnext(conskbd_consqueue, mp);
1203 else
1204 freemsg(mp);
1206 conskbd_idle_stamp = gethrestime_sec();
1207 break;
1209 case M_IOCACK:
1210 case M_IOCNAK:
1211 iocp = (struct iocblk *)mp->b_rptr;
1212 lqs = (conskbd_lower_queue_t *)q->q_ptr;
1214 DPRINTF(PRINT_L1, PRINT_MASK_ALL, ("conskbdlrput: "
1215 "ACK/NAK - cmd 0x%x\n", iocp->ioc_cmd));
1217 conskbd_lqs_ack_complete(lqs, mp);
1218 break;
1220 case M_ERROR:
1221 case M_HANGUP:
1222 default:
1223 freemsg(mp); /* anything useful here? */
1224 break;
1227 } /* conskbdlrput() */
1230 /* ARGSUSED */
1231 static int
1232 conskbd_kstat_update(kstat_t *ksp, int rw)
1234 if (rw == KSTAT_WRITE)
1235 return (EACCES);
1237 conskbd_kstat.idle_sec.value.l = gethrestime_sec() - conskbd_idle_stamp;
1239 return (0);
1241 } /* conskbd_kstat_update() */
1244 * STREAMS architecuture provides guarantee that the ID of each
1245 * message, iocblk.ioc_id, in a stream is unique. The following
1246 * routine performes the task: When receive request from upstream,
1247 * it saves the request in a global link list, clones the request,
1248 * and then sends a copy of the request to each of lower queues
1249 * which are plumbed into conskbd. And then, when receives responses
1250 * from lower queues in conskbdlrput() routine, we can know the
1251 * request matching received responses by searching the global linked
1252 * list to find the request which has the same message ID of the
1253 * response. Then, when all lower queues response this request, we
1254 * give a response to upstreams based the following policy:
1255 * If any one of lower queues acks our reuqest, then we return ack
1256 * to upstreams; only if all lower queues nak our request, we return
1257 * nak to upstreams. If all responses are nak, the error number of
1258 * the first response is sent to upstream.
1260 static void
1261 conskbd_handle_downstream_msg(queue_t *q, mblk_t *mp)
1263 conskbd_pending_msg_t *msg;
1264 conskbd_lower_queue_t *lqs;
1265 struct iocblk *iocp;
1266 mblk_t *clonemp;
1267 int retry;
1269 if (conskbd.conskbd_lqueue_nums == 0) {
1270 miocnak(q, mp, 0, EINVAL);
1271 return;
1274 msg = (conskbd_pending_msg_t *)
1275 kmem_zalloc(sizeof (conskbd_pending_msg_t), KM_SLEEP);
1276 mutex_init(&msg->kpm_lock, NULL, MUTEX_DRIVER, NULL);
1277 lqs = conskbd.conskbd_lqueue_list;
1278 iocp = (struct iocblk *)mp->b_rptr;
1280 ASSERT(iocp->ioc_cmd == CONSOPENPOLLEDIO ||
1281 iocp->ioc_cmd == CONSCLOSEPOLLEDIO ||
1282 iocp->ioc_cmd == KIOCCMD ||
1283 iocp->ioc_cmd == KIOCMKTONE);
1285 msg->kpm_upper_queue = q;
1286 msg->kpm_req_msg = mp;
1287 msg->kpm_req_id = iocp->ioc_id;
1288 msg->kpm_req_cmd = iocp->ioc_cmd;
1289 msg->kpm_req_nums = conskbd.conskbd_lqueue_nums;
1290 conskbd_mux_enqueue_msg(msg);
1292 for (retry = 0, lqs = conskbd.conskbd_lqueue_list; lqs; ) {
1295 * if a lower physical keyboard is not in polled I/O
1296 * mode, we couldn't send CONSCLOSEPOLLEDIO to it,
1297 * otherwise, system will panic.
1299 if (iocp->ioc_cmd == CONSCLOSEPOLLEDIO &&
1300 lqs->lqs_polledio == NULL) {
1301 lqs = lqs->lqs_next;
1302 msg->kpm_req_nums --;
1303 retry = 0;
1304 continue;
1307 clonemp = copymsg(mp);
1308 if (clonemp != NULL) {
1309 if (putq(lqs->lqs_queue, clonemp) == 1) {
1310 lqs = lqs->lqs_next;
1311 retry = 0;
1312 continue;
1316 * failed to invoke putq(), retry.
1318 freemsg(clonemp);
1322 * During testing it was observed that occasionally
1323 * copymsg() would fail during boot. The reason for
1324 * these failures is unknown. Since we really want
1325 * to successfully plumb up all the attached keyboards
1326 * during boot we do a best effort here by retrying
1327 * the copymsg() call in the hopes that it will
1328 * succeeded upon subsequent invocations.
1330 * If all the calls to copymsg() fails, it will cause
1331 * the corresponding keyboard to be unavailable, or
1332 * or behave weirdly,
1334 * 1) for CONSOPENPOLLEDIO
1335 * if copymsg()fails, the corresponding keyboard
1336 * is not available in polled I/O mode once
1337 * entering kmdb;
1338 * 2) for CONSCLOSEPOLLEDIO
1339 * if copymsg() fails, the corresponding keyboard
1340 * is not available in normal mode once returning
1341 * from kmdb;
1342 * 3) for KIOCCMD
1343 * 3.1) for KBD_CMD_NOBELL
1344 * there's no beep in USB and PS2 keyboard,
1345 * this ioctl actually disables the beep on
1346 * system mainboard. Note that all the cloned
1347 * messages sent down to lower queues do the
1348 * same job for system mainboard. Therefore,
1349 * even if we fail to send this ioctl to most
1350 * of lower queues, the beep still would be
1351 * disabled. So, no trouble exists here.
1352 * 3.2) for others
1353 * nothing;
1355 * However, all cases could be resume next time when the
1356 * same request comes again.
1358 if (retry ++ >= 5) {
1359 dev_t devt;
1360 char path[MAXPATHLEN + 1];
1362 devt = lqs->lqs_queue->q_stream->sd_vnode->v_rdev;
1363 switch (iocp->ioc_cmd) {
1364 case CONSOPENPOLLEDIO:
1365 if (ddi_dev_pathname(devt, S_IFCHR,
1366 path) == DDI_SUCCESS)
1367 cmn_err(CE_WARN, "conskbd: "
1368 "keyboard is not available"
1369 " for system debugging: %s",
1370 path);
1371 break;
1373 case CONSCLOSEPOLLEDIO:
1374 if (ddi_dev_pathname(devt, S_IFCHR,
1375 path) == DDI_SUCCESS)
1376 cmn_err(CE_WARN, "conskbd: "
1377 "keyboard is not available:"
1378 " %s", path);
1379 break;
1381 default:
1382 break;
1384 msg->kpm_req_nums --;
1385 lqs = lqs->lqs_next;
1386 retry = 0;
1390 if (msg->kpm_req_nums == 0) {
1391 conskbd_mux_dequeue_msg(msg);
1392 kmem_free(msg, sizeof (*msg));
1393 miocnak(q, mp, 0, ENOMEM);
1396 } /* conskbd_handle_downstream_msg() */
1399 static void
1400 conskbd_ioc_plink(queue_t *q, mblk_t *mp)
1402 mblk_t *req;
1403 queue_t *lowque;
1404 struct linkblk *linkp;
1405 conskbd_lower_queue_t *lqs;
1407 lqs = kmem_zalloc(sizeof (*lqs), KM_SLEEP);
1408 ASSERT(lqs->lqs_state == LQS_UNINITIALIZED);
1410 linkp = (struct linkblk *)mp->b_cont->b_rptr;
1411 lowque = linkp->l_qbot;
1413 lqs->lqs_queue = lowque;
1414 lqs->lqs_pending_plink = mp;
1415 lqs->lqs_pending_queue = q;
1417 req = mkiocb(CONSSETKBDTYPE);
1418 if (req == NULL) {
1419 miocnak(q, mp, 0, ENOMEM);
1420 kmem_free(lqs, sizeof (*lqs));
1421 return;
1424 req->b_cont = allocb(sizeof (int), BPRI_MED);
1425 if (req->b_cont == NULL) {
1426 freemsg(req);
1427 miocnak(q, mp, 0, ENOMEM);
1428 kmem_free(lqs, sizeof (*lqs));
1429 return;
1432 lowque->q_ptr = lqs;
1433 OTHERQ(lowque)->q_ptr = lqs;
1434 *(int *)req->b_cont->b_wptr = KB_USB;
1435 req->b_cont->b_wptr += sizeof (int);
1437 lqs->lqs_state = LQS_KIOCTYPE_ACK_PENDING;
1439 if (putq(lowque, req) != 1) {
1440 freemsg(req);
1441 miocnak(lqs->lqs_pending_queue,
1442 lqs->lqs_pending_plink, 0, ENOMEM);
1443 lowque->q_ptr = NULL;
1444 OTHERQ(lowque)->q_ptr = NULL;
1445 kmem_free(lqs, sizeof (*lqs));
1448 } /* conskbd_ioc_plink() */
1451 static void
1452 conskbd_ioc_punlink(queue_t *q, mblk_t *mp)
1454 int index;
1455 struct linkblk *linkp;
1456 conskbd_lower_queue_t *lqs;
1457 conskbd_lower_queue_t *prev;
1459 linkp = (struct linkblk *)mp->b_cont->b_rptr;
1460 prev = conskbd.conskbd_lqueue_list;
1461 for (lqs = prev; lqs; lqs = lqs->lqs_next) {
1462 if (lqs->lqs_queue == linkp->l_qbot) {
1463 if (prev == lqs)
1464 conskbd.conskbd_lqueue_list =
1465 lqs->lqs_next;
1466 else
1467 prev->lqs_next = lqs->lqs_next;
1469 lqs->lqs_queue->q_ptr = NULL;
1470 OTHERQ(lqs->lqs_queue)->q_ptr = NULL;
1471 conskbd.conskbd_lqueue_nums --;
1472 if (conskbd.conskbd_lqueue_nums == 0) {
1473 kbd_layout_bak = conskbd.conskbd_layout;
1474 conskbd.conskbd_layout = -1;
1477 for (index = 0; index < KBTRANS_KEYNUMS_MAX; index ++) {
1478 if (lqs->lqs_key_state[index] == KEY_PRESSED)
1479 kbtrans_streams_key(
1480 conskbd.conskbd_kbtrans,
1481 index,
1482 KEY_RELEASED);
1485 kmem_free(lqs, sizeof (*lqs));
1486 miocack(q, mp, 0, 0);
1487 return;
1489 prev = lqs;
1491 miocnak(q, mp, 0, EINVAL);
1493 } /* conskbd_ioc_punlink() */
1496 * Every physical keyboard has a corresponding STREAMS queue. We call this
1497 * queue lower queue. Every lower queue has a state, refer to conskbd.h file
1498 * about "enum conskbd_lqs_state".
1499 * The following routine is used to handle response messages from lower queue.
1500 * When receiving ack/nak message from lower queue(s), the routine determines
1501 * the passage for it according to the current state of this lower queue.
1503 static void
1504 conskbd_lqs_ack_complete(conskbd_lower_queue_t *lqs, mblk_t *mp)
1506 switch (lqs->lqs_state) {
1508 /* S6: working in virtual keyboard mode, multi-keyboards are usable */
1509 case LQS_INITIALIZED:
1510 conskbd_mux_upstream_msg(lqs, mp);
1511 break;
1513 /* S5: working in legacy mode, only one keyboard is usable */
1514 case LQS_INITIALIZED_LEGACY:
1515 conskbd_legacy_upstream_msg(lqs, mp);
1516 break;
1518 /* S4: wait lower queue to acknowledge KIOCSLED/KIOCGLED message */
1519 case LQS_KIOCSLED_ACK_PENDING:
1520 conskbd_kiocsled_complete(lqs, mp);
1521 break;
1523 /* S3: wait lower queue to acknowledge KIOCLAYOUT message */
1524 case LQS_KIOCLAYOUT_ACK_PENDING:
1525 conskbd_kioclayout_complete(lqs, mp);
1526 break;
1528 /* S2: wait lower queue to acknowledge KIOCTRANS message */
1529 case LQS_KIOCTRANS_ACK_PENDING:
1530 conskbd_kioctrans_complete(lqs, mp);
1531 break;
1533 /* S1: wait lower queue to acknowledge KIOCTYPE message */
1534 case LQS_KIOCTYPE_ACK_PENDING:
1535 conskbd_kioctype_complete(lqs, mp);
1536 break;
1538 /* if reaching here, there must be a error */
1539 default:
1540 freemsg(mp);
1541 cmn_err(CE_WARN, "conskbd: lqs_ack_complete() state error");
1542 break;
1545 } /* conskbd_lqs_ack_complete() */
1548 static void
1549 conskbd_kioctype_complete(conskbd_lower_queue_t *lqs, mblk_t *mp)
1551 struct iocblk *iocp;
1552 mblk_t *req;
1553 queue_t *lowerque;
1554 int err = ENOMEM;
1556 ASSERT(lqs->lqs_pending_plink);
1557 ASSERT(lqs->lqs_state == LQS_KIOCTYPE_ACK_PENDING);
1559 lowerque = lqs->lqs_queue;
1561 switch (mp->b_datap->db_type) {
1562 case M_IOCACK:
1563 req = mkiocb(KIOCTRANS);
1564 if (req == NULL) {
1565 goto err_exit;
1568 req->b_cont = allocb(sizeof (int), BPRI_MED);
1569 if (req->b_cont == NULL) {
1570 freemsg(req);
1571 goto err_exit;
1574 /* Set the translate mode to TR_UNTRANS_EVENT */
1575 *(int *)req->b_cont->b_wptr = TR_UNTRANS_EVENT;
1576 req->b_cont->b_wptr += sizeof (int);
1578 /* Ready to handle the response to KIOCTRANS */
1579 lqs->lqs_state = LQS_KIOCTRANS_ACK_PENDING;
1581 if (putq(lowerque, req) != 1) {
1582 freemsg(req);
1583 goto err_exit;
1585 freemsg(mp);
1586 return;
1588 case M_IOCNAK:
1590 * The lower keyboard driver can't mimic USB keyboard,
1591 * that's say, the physical keyboard is an old one, such
1592 * as TYPE 3/4/5 one. In this case, the virtual keyboard
1593 * is disabled, and the data from lower keyboard driver
1594 * will bypass the conskbd module.
1598 * if there is any other keyborad already linked under the
1599 * conskbd, we reject the current one.
1601 if (conskbd.conskbd_lqueue_nums > 0) {
1602 iocp = (struct iocblk *)mp->b_rptr;
1603 err = iocp->ioc_error;
1604 goto err_exit;
1608 * link this keyboard under conskbd.
1610 qwriter(lowerque, mp, conskbd_link_lowque_legacy, PERIM_OUTER);
1611 return;
1614 err_exit:
1615 miocnak(lqs->lqs_pending_queue, lqs->lqs_pending_plink, 0, err);
1616 lowerque->q_ptr = NULL;
1617 OTHERQ(lowerque)->q_ptr = NULL;
1618 kmem_free(lqs, sizeof (*lqs));
1619 freemsg(mp);
1621 } /* conskbd_kioctype_complete() */
1623 static void
1624 conskbd_kioctrans_complete(conskbd_lower_queue_t *lqs, mblk_t *mp)
1626 struct iocblk *iocp;
1627 mblk_t *req;
1628 queue_t *lowerque;
1629 int err = ENOMEM;
1631 ASSERT(lqs->lqs_pending_plink != NULL);
1632 ASSERT(lqs->lqs_state == LQS_KIOCTRANS_ACK_PENDING);
1634 lowerque = lqs->lqs_queue;
1636 switch (mp->b_datap->db_type) {
1637 case M_IOCACK:
1638 req = mkiocb(KIOCLAYOUT);
1639 if (req == NULL) {
1640 goto err_exit;
1643 req->b_cont = allocb(sizeof (int), BPRI_MED);
1644 if (req->b_cont == NULL) {
1645 freemsg(req);
1646 goto err_exit;
1649 /* waiting for response to KIOCLAYOUT */
1650 lqs->lqs_state = LQS_KIOCLAYOUT_ACK_PENDING;
1651 if (putq(lqs->lqs_queue, req) != 1) {
1652 freemsg(req);
1653 goto err_exit;
1655 freemsg(mp);
1656 return;
1658 case M_IOCNAK:
1659 iocp = (struct iocblk *)mp->b_rptr;
1660 err = iocp->ioc_error;
1661 goto err_exit;
1664 err_exit:
1665 miocnak(lqs->lqs_pending_queue, lqs->lqs_pending_plink, 0, err);
1666 lowerque->q_ptr = NULL;
1667 OTHERQ(lowerque)->q_ptr = NULL;
1668 kmem_free(lqs, sizeof (*lqs));
1669 freemsg(mp);
1671 } /* conskbd_kioctrans_complete() */
1674 * Allocate a firm event
1676 static mblk_t *
1677 conskbd_alloc_firm_event(ushort_t id, int value)
1679 mblk_t *mb;
1680 Firm_event *fe;
1682 if ((mb = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
1683 fe = (Firm_event *)mb->b_wptr;
1684 fe->id = id;
1685 fe->pair_type = FE_PAIR_NONE;
1686 fe->pair = NULL;
1687 fe->value = value;
1688 mb->b_wptr += sizeof (Firm_event);
1691 return (mb);
1694 static void
1695 conskbd_kioclayout_complete(conskbd_lower_queue_t *lqs, mblk_t *mp)
1697 mblk_t *req;
1698 int layout;
1699 boolean_t fail;
1701 ASSERT(lqs->lqs_pending_plink != NULL);
1702 ASSERT(lqs->lqs_state == LQS_KIOCLAYOUT_ACK_PENDING);
1704 switch (mp->b_datap->db_type) {
1705 case M_IOCACK:
1706 if (miocpullup(mp, sizeof (int)) == 0) {
1707 layout = *(int *)mp->b_cont->b_rptr;
1709 * We just accept the layout of the first keyboard
1710 * requesting to be linked under conskbd. If current
1711 * keyboard is the first one, and if we get right
1712 * layout from it, we set conskbd's layout
1714 if (layout != -1 && conskbd.conskbd_layout == -1) {
1715 if (layout == 0) {
1716 conskbd.conskbd_layout = kbd_layout_bak;
1717 } else {
1718 conskbd.conskbd_layout = layout;
1719 if (layout == kbd_layout_bak) {
1720 break;
1722 if ((req = conskbd_alloc_firm_event(
1723 KEYBOARD_LAYOUT_CHANGE,
1724 layout)) != NULL) {
1725 if (conskbd.conskbd_directio) {
1726 putnext(
1727 conskbd_regqueue,
1728 req);
1729 } else if (conskbd_consqueue
1730 != NULL) {
1731 putnext(
1732 conskbd_consqueue,
1733 req);
1734 } else {
1735 freemsg(req);
1741 break;
1744 /* if fail, leave conskbd's layout as it is */
1745 case M_IOCNAK:
1746 break;
1749 fail = B_TRUE;
1751 if (conskbd.conskbd_led_state == -1)
1752 req = mkiocb(KIOCGLED);
1753 else
1754 req = mkiocb(KIOCSLED);
1756 if (req) {
1757 req->b_cont = allocb(sizeof (uchar_t), BPRI_MED);
1758 if (req->b_cont) {
1759 if (conskbd.conskbd_led_state != -1) {
1760 *(uchar_t *)req->b_cont->b_wptr =
1761 conskbd.conskbd_led_state;
1762 req->b_cont->b_wptr += sizeof (uchar_t);
1765 /* waiting for response to KIOCSLED */
1766 lqs->lqs_state = LQS_KIOCSLED_ACK_PENDING;
1767 if (putq(lqs->lqs_queue, req) == 1) {
1768 fail = B_FALSE;
1769 } else {
1770 freemsg(req);
1773 } else {
1774 freemsg(req);
1778 if (fail) {
1780 * If fail to allocate KIOCSLED/KIOCGLED message or put
1781 * the message into lower queue, we immediately link
1782 * current keyboard under conskbd. Thus, even if fails
1783 * to set/get LED, this keyboard could be available.
1785 qwriter(lqs->lqs_queue,
1786 mp, conskbd_link_lowque_virt, PERIM_OUTER);
1787 } else {
1788 freemsg(mp);
1791 } /* conskbd_kioclayout_complete() */
1794 static void
1795 conskbd_kiocsled_complete(conskbd_lower_queue_t *lqs, mblk_t *mp)
1797 int led_state;
1799 ASSERT(lqs->lqs_pending_plink != NULL);
1800 ASSERT(lqs->lqs_state == LQS_KIOCSLED_ACK_PENDING);
1802 if (conskbd.conskbd_led_state == -1) {
1803 switch (mp->b_datap->db_type) {
1804 case M_IOCACK:
1805 if (miocpullup(mp, sizeof (uchar_t)) == 0) {
1806 led_state = *(uchar_t *)mp->b_cont->b_rptr;
1807 conskbd.conskbd_led_state = led_state;
1808 kbtrans_streams_setled(conskbd.conskbd_kbtrans,
1809 led_state);
1811 break;
1813 /* if fail, leave conskbd's led_state as it is */
1814 case M_IOCNAK:
1815 break;
1820 * Basically, failure of setting/getting LED is not a fatal
1821 * error, so we will plumb the lower queue into conskbd whether
1822 * setting/getting LED succeeds or fails.
1824 qwriter(lqs->lqs_queue, mp, conskbd_link_lowque_virt, PERIM_OUTER);
1826 } /* conskbd_kiocsled_complete() */
1829 static void
1830 conskbd_mux_upstream_msg(conskbd_lower_queue_t *lqs, mblk_t *mp)
1832 conskbd_pending_msg_t *msg;
1833 struct iocblk *iocp;
1834 int error;
1835 dev_t devt;
1836 char path[MAXPATHLEN + 1];
1838 ASSERT(lqs->lqs_state == LQS_INITIALIZED);
1839 msg = conskbd_mux_find_msg(mp);
1841 if (!msg) {
1843 * Here we discard the response if:
1845 * 1. It's an KIOCSLED request; see conskbd_streams_setled().
1846 * 2. The application has already closed the upper stream;
1847 * see conskbdclose()
1849 freemsg(mp);
1850 return;
1854 * We use the b_next field of mblk_t structure to link all
1855 * response coming from lower queues into a linkage list,
1856 * and make use of the b_prev field to save a pointer to
1857 * the lower queue from which the current response message
1858 * comes.
1860 ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
1861 mutex_enter(&msg->kpm_lock);
1862 mp->b_next = msg->kpm_resp_list;
1863 mp->b_prev = (mblk_t *)lqs;
1864 msg->kpm_resp_list = mp;
1865 msg->kpm_resp_nums ++;
1867 if (msg->kpm_resp_nums < msg->kpm_req_nums) {
1868 mutex_exit(&msg->kpm_lock);
1869 return;
1872 ASSERT(msg->kpm_resp_nums == msg->kpm_req_nums);
1873 ASSERT(mp == msg->kpm_resp_list);
1875 mutex_exit(&msg->kpm_lock);
1877 conskbd_mux_dequeue_msg(msg);
1881 * Here, we have the policy that, if any one lower queue ACK
1882 * our reuqest, then we return ACK to upstreams; only if all
1883 * lower queues NAK our request, we return NAK to upstreams.
1884 * if all responses are nak, the errno of the first response
1885 * is sent to upstreams
1887 ASSERT(mp->b_rptr);
1888 error = ((struct iocblk *)mp->b_rptr)->ioc_error;
1890 switch (msg->kpm_req_cmd) {
1891 case CONSOPENPOLLEDIO:
1893 * Here, we can safely ignore the NAK message. If any one lower
1894 * queue returns NAK, the pointer to the corresponding polledio
1895 * structure will remain null, that's say lqs->lqs_polledio =
1896 * null. When we need to invoke polled I/O interface, we will
1897 * check if the pointer is null.
1899 for (mp = msg->kpm_resp_list; mp; ) {
1900 cons_polledio_t *polledio;
1902 msg->kpm_resp_list = mp->b_next;
1903 lqs = (conskbd_lower_queue_t *)mp->b_prev;
1904 devt = lqs->lqs_queue->q_stream->sd_vnode->v_rdev;
1905 if (mp->b_datap->db_type == M_IOCACK) {
1906 polledio = *(struct cons_polledio **)
1907 mp->b_cont->b_rptr;
1908 if (polledio->cons_polledio_version ==
1909 CONSPOLLEDIO_V1) {
1910 lqs->lqs_polledio = polledio;
1911 error = 0;
1912 } else {
1914 * USB and PS2 keyboard drivers should
1915 * use the same cons_polledio structure
1916 * as conskbd.
1918 if (ddi_dev_pathname(devt, S_IFCHR,
1919 path) == DDI_SUCCESS) {
1920 cmn_err(CE_WARN, "keyboard "
1921 "driver does not support "
1922 "system debugging: %s",
1923 path);
1925 error = EINVAL;
1927 } else {
1928 if (ddi_dev_pathname(devt, S_IFCHR, path) ==
1929 DDI_SUCCESS) {
1930 cmn_err(CE_WARN, "conskbd: keyboard is"
1931 " not available for system"
1932 " debugging: %s", path);
1935 mp->b_next = NULL;
1936 mp->b_prev = NULL;
1937 freemsg(mp);
1938 mp = msg->kpm_resp_list;
1941 mp = msg->kpm_req_msg;
1942 if (error == 0) {
1943 *(struct cons_polledio **)mp->b_cont->b_rptr =
1944 &conskbd.conskbd_polledio;
1946 break;
1948 case CONSCLOSEPOLLEDIO:
1949 for (mp = msg->kpm_resp_list; mp; ) {
1950 msg->kpm_resp_list = mp->b_next;
1951 lqs = (conskbd_lower_queue_t *)mp->b_prev;
1952 if (mp->b_datap->db_type == M_IOCACK) {
1953 lqs->lqs_polledio = NULL;
1954 error = 0;
1955 } else {
1956 devt =
1957 lqs->lqs_queue->q_stream->sd_vnode->v_rdev;
1959 if (ddi_dev_pathname(devt, S_IFCHR, path) ==
1960 DDI_SUCCESS) {
1961 cmn_err(CE_WARN, "conskbd: keyboard is"
1962 " not available: %s", path);
1966 mp->b_next = NULL;
1967 mp->b_prev = NULL;
1968 freemsg(mp);
1969 mp = msg->kpm_resp_list;
1971 break;
1973 case KIOCCMD:
1974 case KIOCMKTONE:
1975 for (mp = msg->kpm_resp_list; mp; ) {
1976 msg->kpm_resp_list = mp->b_next;
1978 if (mp->b_datap->db_type == M_IOCACK)
1979 error = 0;
1980 mp->b_next = NULL;
1981 mp->b_prev = NULL;
1982 freemsg(mp);
1983 mp = msg->kpm_resp_list;
1985 break;
1987 default: /* it is impossible to reach here */
1988 cmn_err(CE_WARN, "conskbd: unexpected ioctl reply");
1991 mp = msg->kpm_req_msg;
1992 if (error == 0) {
1993 mp->b_datap->db_type = M_IOCACK;
1994 } else {
1995 mp->b_datap->db_type = M_IOCNAK;
1997 iocp = (struct iocblk *)mp->b_rptr;
1998 iocp->ioc_error = error;
1999 qreply(msg->kpm_upper_queue, mp);
2000 mutex_destroy(&msg->kpm_lock);
2001 kmem_free(msg, sizeof (*msg));
2003 } /* conskbd_mux_upstream_msg() */
2005 static void
2006 conskbd_link_lowque_legacy(queue_t *lowque, mblk_t *mp)
2008 conskbd_lower_queue_t *lqs;
2010 freemsg(mp);
2013 * Bypass the virutal keyboard for old hardware,
2014 * Now, only current legacy keyboard can be linked
2015 * under conskbd
2017 conskbd.conskbd_bypassed = B_TRUE;
2020 * Link the lower queue under conskbd
2022 lqs = (conskbd_lower_queue_t *)lowque->q_ptr;
2023 lqs->lqs_state = LQS_INITIALIZED_LEGACY;
2024 lqs->lqs_next = conskbd.conskbd_lqueue_list;
2025 conskbd.conskbd_lqueue_list = lqs;
2026 conskbd.conskbd_lqueue_nums++;
2028 mioc2ack(lqs->lqs_pending_plink, NULL, 0, 0);
2029 qreply(lqs->lqs_pending_queue, lqs->lqs_pending_plink);
2031 } /* conskbd_link_lowque_legacy() */
2033 static void
2034 conskbd_link_lowque_virt(queue_t *lowque, mblk_t *mp)
2036 int index;
2037 conskbd_lower_queue_t *lqs;
2039 freemsg(mp);
2041 lqs = (conskbd_lower_queue_t *)lowque->q_ptr;
2043 ASSERT(lqs->lqs_queue == lowque);
2044 ASSERT(lqs->lqs_pending_plink != NULL);
2047 * Now, link the lower queue under conskbd
2049 for (index = 0; index < KBTRANS_KEYNUMS_MAX; index ++) {
2050 lqs->lqs_key_state[index] = KEY_RELEASED;
2052 lqs->lqs_next = conskbd.conskbd_lqueue_list;
2053 lqs->lqs_state = LQS_INITIALIZED;
2054 conskbd.conskbd_lqueue_nums++;
2055 conskbd.conskbd_lqueue_list = lqs;
2056 mioc2ack(lqs->lqs_pending_plink, NULL, 0, 0);
2057 qreply(lqs->lqs_pending_queue, lqs->lqs_pending_plink);
2059 } /* conskbd_link_lowque_virt() */
2061 /*ARGSUSED*/
2062 static void
2063 conskbd_legacy_upstream_msg(conskbd_lower_queue_t *lqs, mblk_t *mp)
2065 struct iocblk *iocp;
2067 ASSERT(lqs && lqs->lqs_state == LQS_INITIALIZED_LEGACY);
2070 * We assume that all of the ioctls are headed to the
2071 * conskbd_regqueue if it is open. We are intercepting a few ioctls
2072 * that we know belong to conskbd_consqueue, and sending them there.
2073 * Any other, new ioctls that have to be routed to conskbd_consqueue
2074 * should be added to this list.
2076 iocp = (struct iocblk *)mp->b_rptr;
2078 if ((iocp->ioc_cmd == CONSOPENPOLLEDIO) ||
2079 (iocp->ioc_cmd == CONSCLOSEPOLLEDIO)) {
2081 DPRINTF(PRINT_L1, PRINT_MASK_ALL,
2082 ("conskbd_legacy_upstream_msg: "
2083 "CONSOPEN/CLOSEPOLLEDIO ACK/NAK\n"));
2084 putnext(conskbd_consqueue, mp);
2086 } else if (conskbd_regqueue != NULL) {
2087 DPRINTF(PRINT_L1, PRINT_MASK_ALL,
2088 ("conskbd_legacy_upstream_msg: conskbd_regqueue != NULL"));
2090 putnext(conskbd_regqueue, mp);
2092 } else if (conskbd_consqueue != NULL) {
2093 DPRINTF(PRINT_L1, PRINT_MASK_ALL,
2094 ("conskbd_legacy_upstream_msg: conskbd_consqueue != NULL"));
2095 putnext(conskbd_consqueue, mp);
2096 } else {
2097 /* if reached here, it must be a error */
2098 cmn_err(CE_WARN,
2099 "kb: no destination for IOCACK/IOCNAK!");
2100 freemsg(mp);
2103 } /* conskbd_legacy_upstream_msg() */
2106 * This routine is a callback routine for kbtrans module to set LED.
2107 * Kbtrans will invoke it in two cases:
2109 * 1) application initiated request
2110 * A KIOCSLED ioctl is sent by an application. The ioctl will be
2111 * be prcoessed by queue service procedure conskbduwsrv(), which
2112 * in turn calls kbtrans to process the ioctl. Then kbtrans invokes
2113 * conskbd_streams_setled() to set LED, after that, kbtrans will
2114 * return an ACK message to upper module.
2116 * 2) Kbtrans initiated the request
2117 * When conskbd works in TR_ASCII translation mode, if anyone of
2118 * CapsLock, NumberLock and Compose keys is pressed, kbtrans need
2119 * to set LED. In this case, there is no ioctl from upper module.
2120 * There is no requirement to send response to somebody.
2122 * In first case, kbtrans will send response to upper module; and in the
2123 * second, we don't need to send response. So conskbd_streams_setled()
2124 * has no return value.
2126 static void
2127 conskbd_streams_setled(struct kbtrans_hardware *hw, int led_state)
2129 conskbd_state_t *conskbdp = (conskbd_state_t *)hw;
2130 conskbd_lower_queue_t *lqs;
2131 mblk_t *req;
2133 ASSERT(&conskbd == conskbdp);
2135 if (led_state == -1)
2136 return;
2138 conskbdp->conskbd_led_state = led_state;
2141 * Basically, failing to set LED is not a fatal error, we just skip
2142 * it if this happens.
2144 for (lqs = conskbdp->conskbd_lqueue_list; lqs; lqs = lqs->lqs_next) {
2145 req = mkiocb(KIOCSLED);
2147 if (!req) {
2148 continue;
2151 req->b_cont = allocb(sizeof (uchar_t), BPRI_MED);
2152 if (!req->b_cont) {
2153 freemsg(req);
2154 continue;
2156 *(uchar_t *)req->b_cont->b_wptr = led_state;
2157 req->b_cont->b_wptr += sizeof (uchar_t);
2158 if (putq(lqs->lqs_queue, req) != 1)
2159 freemsg(req);
2162 } /* conskbd_streams_setled() */
2164 static void
2165 conskbd_polledio_setled(struct kbtrans_hardware *hw, int led_state)
2167 conskbd_state_t *conskbdp = (conskbd_state_t *)hw;
2168 struct cons_polledio *cb;
2169 conskbd_lower_queue_t *lqs;
2171 for (lqs = conskbdp->conskbd_lqueue_list; lqs; lqs = lqs->lqs_next) {
2172 cb = lqs->lqs_polledio;
2173 if ((cb != NULL) && (cb->cons_polledio_setled != NULL)) {
2174 cb->cons_polledio_setled(cb->cons_polledio_argument,
2175 led_state);
2179 } /* conskbd_polledio_setled() */
2181 static boolean_t
2182 conskbd_polled_keycheck(struct kbtrans_hardware *hw,
2183 kbtrans_key_t *keycode, enum keystate *state)
2185 conskbd_state_t *conskbdp = (conskbd_state_t *)hw;
2186 struct cons_polledio *cb;
2187 conskbd_lower_queue_t *lqs;
2188 boolean_t ret = B_FALSE;
2190 for (ret = B_FALSE, lqs = conskbdp->conskbd_lqueue_list; lqs != NULL;
2191 lqs = lqs->lqs_next) {
2192 cb = lqs->lqs_polledio;
2193 if ((cb != NULL) &&
2194 (cb->cons_polledio_keycheck != NULL)) {
2195 ret = cb->cons_polledio_keycheck(
2196 cb->cons_polledio_argument, keycode, state);
2199 /* Get a char from lower queue(hardware) ? */
2200 if (ret == B_TRUE) {
2202 /* A legacy keyboard ? */
2203 if (conskbd.conskbd_bypassed == B_TRUE)
2204 break;
2207 * This is the PS2 scancode 0x2B -> USB(49) /
2208 * USB(50) keycode mapping workaround, for
2209 * polled mode.
2211 * There are two possible USB keycode mappings
2212 * for PS2 scancode 0x2B and this workaround
2213 * makes sure that we use the USB keycode that
2214 * does not end up being mapped to a HOLE key
2215 * using the current keyboard translation
2216 * tables.
2218 * See conskbdlrput() for a detailed
2219 * explanation of the problem.
2221 if (*keycode == 49 || *keycode == 50) {
2222 if (conskbd_keyindex->k_normal[50] == HOLE)
2223 *keycode = 49;
2224 else
2225 *keycode = 50;
2228 break;
2232 return (ret);
2234 } /* conskbd_polled_keycheck() */
2236 static boolean_t
2237 conskbd_override_kbtrans(queue_t *q, mblk_t *mp)
2239 struct iocblk *iocp;
2240 int directio;
2241 int error;
2243 if (mp->b_datap->db_type != M_IOCTL)
2244 return (B_FALSE);
2246 iocp = (struct iocblk *)mp->b_rptr;
2248 switch (iocp->ioc_cmd) {
2249 case KIOCGDIRECT: {
2251 * Don't let the kbtrans-based code see this; it will
2252 * respond incorrectly.
2254 register mblk_t *datap;
2256 if ((datap = allocb((int)sizeof (int), BPRI_MED)) == NULL) {
2257 miocnak(q, mp, 0, ENOMEM);
2258 return (B_TRUE);
2261 *(int *)datap->b_wptr = conskbd.conskbd_directio;
2262 datap->b_wptr += sizeof (int);
2263 if (mp->b_cont) {
2264 freemsg(mp->b_cont);
2265 mp->b_cont = NULL;
2267 mp->b_cont = datap;
2268 miocack(q, mp, sizeof (int), 0);
2269 return (B_TRUE);
2272 case KIOCSDIRECT:
2274 * Peek at this, set our variables, and then let the kbtrans
2275 * based code see it and respond to it.
2277 error = miocpullup(mp, sizeof (int));
2278 if (error != 0) {
2279 return (B_FALSE);
2282 directio = *(int *)mp->b_cont->b_rptr;
2283 if (directio != 0 && directio != 1) {
2284 miocnak(q, mp, 0, EINVAL);
2285 return (B_TRUE);
2287 conskbd.conskbd_directio = directio;
2289 if (conskbd.conskbd_directio) {
2290 kbtrans_streams_set_queue(
2291 conskbd.conskbd_kbtrans, conskbd_regqueue);
2292 } else {
2293 kbtrans_streams_set_queue(
2294 conskbd.conskbd_kbtrans, conskbd_consqueue);
2298 * Let the kbtrans-based code see this and respond to it.
2300 return (B_FALSE);
2302 default:
2303 return (B_FALSE);
2306 } /* conskbd_override_kbtrans() */
2309 static void
2310 conskbd_polledio_enter(cons_polledio_arg_t arg)
2312 conskbd_state_t *conskbdp;
2313 struct cons_polledio *cb;
2314 conskbd_lower_queue_t *lqs;
2316 conskbdp = (conskbd_state_t *)arg;
2317 for (lqs = conskbdp->conskbd_lqueue_list; lqs; lqs = lqs->lqs_next) {
2318 cb = lqs->lqs_polledio;
2319 if ((cb != NULL) && (cb->cons_polledio_enter != NULL)) {
2320 cb->cons_polledio_enter(cb->cons_polledio_argument);
2324 } /* conskbd_polledio_enter() */
2326 static void
2327 conskbd_polledio_exit(cons_polledio_arg_t arg)
2329 conskbd_state_t *conskbdp;
2330 struct cons_polledio *cb;
2331 conskbd_lower_queue_t *lqs;
2333 conskbdp = (conskbd_state_t *)arg;
2334 for (lqs = conskbdp->conskbd_lqueue_list; lqs; lqs = lqs->lqs_next) {
2335 cb = lqs->lqs_polledio;
2336 if ((cb != NULL) && (cb->cons_polledio_exit != NULL)) {
2337 cb->cons_polledio_exit(cb->cons_polledio_argument);
2341 } /* conskbd_polledio_exit() */
2343 static int
2344 conskbd_polledio_getchar(cons_polledio_arg_t arg)
2346 conskbd_state_t *conskbdp;
2348 conskbdp = (conskbd_state_t *)arg;
2350 return (kbtrans_getchar(conskbdp->conskbd_kbtrans));
2352 } /* conskbd_polledio_getchar() */
2354 static int
2355 conskbd_polledio_ischar(cons_polledio_arg_t arg)
2357 conskbd_state_t *conskbdp;
2359 conskbdp = (conskbd_state_t *)arg;
2361 return (kbtrans_ischar(conskbdp->conskbd_kbtrans));
2363 } /* conskbd_polledio_ischar() */
2366 static void
2367 conskbd_mux_enqueue_msg(conskbd_pending_msg_t *msg)
2369 mutex_enter(&conskbd_msgq_lock);
2370 msg->kpm_next = conskbd_msg_queue;
2371 conskbd_msg_queue = msg;
2372 mutex_exit(&conskbd_msgq_lock);
2374 } /* conskbd_mux_enqueue_msg() */
2377 * the messages in conskbd_msg_queue we just enqueue
2379 static conskbd_pending_msg_t *
2380 conskbd_mux_find_msg(mblk_t *mp)
2382 conskbd_pending_msg_t *msg;
2383 struct iocblk *iocp;
2384 uint_t id;
2386 mutex_enter(&conskbd_msgq_lock);
2387 msg = conskbd_msg_queue;
2389 iocp = (struct iocblk *)mp->b_rptr;
2390 ASSERT(iocp);
2391 id = iocp->ioc_id;
2392 while (msg && msg->kpm_req_id != id) {
2393 msg = msg->kpm_next;
2395 mutex_exit(&conskbd_msgq_lock);
2397 return (msg);
2399 } /* conskbd_mux_find_msg() */
2402 static void
2403 conskbd_mux_dequeue_msg(conskbd_pending_msg_t *msg)
2405 conskbd_pending_msg_t *prev;
2406 conskbd_pending_msg_t *p;
2408 mutex_enter(&conskbd_msgq_lock);
2409 prev = conskbd_msg_queue;
2411 for (p = prev; p && p != msg; p = p->kpm_next)
2412 prev = p;
2414 ASSERT(p && p == msg);
2416 if (prev == p) {
2417 conskbd_msg_queue = msg->kpm_next;
2418 } else {
2419 prev->kpm_next = p->kpm_next;
2421 p->kpm_next = NULL;
2422 mutex_exit(&conskbd_msgq_lock);
2424 } /* conskbd_mux_dequeue_msg() */
2426 #ifdef DEBUG
2427 /*ARGSUSED*/
2428 void
2429 conskbd_dprintf(const char *fmt, ...)
2431 char buf[256];
2432 va_list ap;
2434 va_start(ap, fmt);
2435 (void) vsprintf(buf, fmt, ap);
2436 va_end(ap);
2438 cmn_err(CE_CONT, "conskbd: %s", buf);
2440 } /* conskbd_dprintf() */
2441 #endif