1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28 /*
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.
35 *
36 *
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.
41 *
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:
47 *
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.
54 */
55 #define KEYMAP_SIZE_VARIABLE
56
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>
81
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);
85
86 /*
87 * Module linkage routines for the kernel
88 */
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 **);
92
93 /*
94 * STREAMS queue processing procedures
95 */
96 static int conskbduwsrv(queue_t *);
97 static int conskbdlwserv(queue_t *);
98 static int 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 *);
101
102
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 */
111 };
112
113 /*
114 * STREAMS queue processing procedure structures
115 */
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 */
125 };
126
127 /* upper write queue processing procedures structuresi */
128 static struct qinit conskbduwinit = {
129 putq, /* qi_putp */
130 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 */
136 };
137
138 /* lower read queue processing procedures structures */
139 static struct qinit conskbdlrinit = {
140 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 */
147 };
148
149 /* lower write processing procedures structures */
150 static struct qinit conskbdlwinit = {
151 putq, /* qi_putp */
152 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 */
158 };
159
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 */
166 };
167
168
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 */
186 };
187
188
189 /*
190 * Device operations structure
191 */
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 */
205 };
206
207 /*
208 * Module linkage information for the kernel.
209 */
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 */
214 };
215
216 /*
217 * Module linkage structure
218 */
219 static struct modlinkage modlinkage = {
220 MODREV_1, /* ml_rev */
221 &modldrv, /* ml_linkage */
222 NULL /* NULL terminates the list */
223 };
224
225 /*
226 * Debug printing
227 */
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)
235
236 /*
237 * Severity levels for printing
238 */
239 #define PRINT_L0 0 /* print every message */
240 #define PRINT_L1 1 /* debug */
241 #define PRINT_L2 2 /* quiet */
242
243 /*
244 * Masks
245 */
246 #define PRINT_MASK_ALL 0xFFFFFFFFU
247 uint_t conskbd_errmask = PRINT_MASK_ALL;
248 uint_t conskbd_errlevel = PRINT_L2;
249
250 #else
251 #define DPRINTF(l, m, args) /* NOTHING */
252 #endif
253 #endif
254
255 /*
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().
261 */
262 static queue_t *conskbd_regqueue; /* regular keyboard queue above us */
263 static queue_t *conskbd_consqueue; /* console queue above us */
264
265
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;
269
270 /*
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.
275 */
276 static struct {
277 kstat_named_t idle_sec; /* seconds since last keystroke */
278 } conskbd_kstat = {
279 { "idle_sec", KSTAT_DATA_LONG, }
280 };
281
282 /*
283 * Local routines prototypes
284 */
285 static int conskbd_kstat_update(kstat_t *, int);
286
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);
293
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 *);
299
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 *);
308
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);
314
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 *);
320
321 /*
322 * Callbacks needed by kbtrans
323 */
324 static struct kbtrans_callbacks conskbd_callbacks = {
325 conskbd_streams_setled,
326 conskbd_polledio_setled,
327 conskbd_polled_keycheck,
328 };
329
330 /*
331 * Single private "global" lock for the few rare conditions
332 * we want single-threaded.
333 */
334 static kmutex_t conskbd_msgq_lock;
335 static conskbd_pending_msg_t *conskbd_msg_queue;
336
337 /*
338 * The software state structure of virtual keyboard.
339 * Currently, only one virtual keyboard is supported.
340 */
341 static conskbd_state_t conskbd = { 0 };
342
343 /* This variable backs up the layout state for non-self-ID keyboards */
344 static int kbd_layout_bak = 0;
345
346 /*
347 * _init()
348 *
349 * Description:
350 * Driver initialization, called when driver is first loaded.
351 * This is how access is initially given to all the static structures.
352 *
353 * Arguments:
354 * None
355 *
356 * Returns:
357 * ddi_soft_state_init() status, see ddi_soft_state_init(9f), or
358 * mod_install() status, see mod_install(9f)
359 */
360 int
_init(void)361 _init(void)
362 {
363 int error;
364
365 error = mod_install(&modlinkage);
366 if (error != 0) {
367 return (error);
368 }
369
370 conskbd_keyindex = kbtrans_usbkb_maptab_init();
371
372 mutex_init(&conskbd_msgq_lock, NULL, MUTEX_DRIVER, NULL);
373
374 return (error);
375
376 } /* _init() */
377
378 /*
379 * _fini()
380 *
381 * Description:
382 * Module de-initialization, called when the driver is to be unloaded.
383 *
384 * Arguments:
385 * None
386 *
387 * Returns:
388 * mod_remove() status, see mod_remove(9f)
389 */
390 int
_fini(void)391 _fini(void)
392 {
393 int error;
394
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);
400
401 return (0);
402
403 } /* _fini() */
404
405 /*
406 * _info()
407 *
408 * Description:
409 * Module information, returns information about the driver.
410 *
411 * Arguments:
412 * modinfo *modinfop Pointer to the opaque modinfo structure
413 *
414 * Returns:
415 * mod_info() status, see mod_info(9f)
416 */
417 int
_info(struct modinfo * modinfop)418 _info(struct modinfo *modinfop)
419 {
420 return (mod_info(&modlinkage, modinfop));
421
422 } /* _info() */
423
424
425 /*
426 * conskbd_attach()
427 *
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).
434 *
435 * Arguments:
436 * dev_info_t *dip Pointer to the device's dev_info struct
437 * ddi_attach_cmd_t cmd Attach command
438 *
439 * Returns:
440 * DDI_SUCCESS The driver was initialized properly
441 * DDI_FAILURE The driver couldn't be initialized properly
442 */
443 /*ARGSUSED*/
444 static int
conskbd_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)445 conskbd_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
446 {
447 kstat_t *ksp;
448
449 switch (cmd) {
450 case DDI_ATTACH:
451 break;
452
453 default:
454 return (DDI_FAILURE);
455
456 }
457 if ((ddi_create_minor_node(devi, "kbd", S_IFCHR,
458 0, DDI_PSEUDO, 0) == 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);
463 }
464 conskbd_dip = devi;
465
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 */
474 }
475
476 conskbd.conskbd_layout = -1; /* invalid layout */
477 conskbd.conskbd_led_state = -1;
478 conskbd.conskbd_bypassed = B_FALSE;
479
480 return (DDI_SUCCESS);
481
482 } /* conskbd_attach() */
483
484 /*
485 * conskbd_detach()
486 *
487 * Description:
488 * Detach an instance of the conskbd driver. In fact, the driver can not
489 * be detached.
490 *
491 * Arguments:
492 * dev_info_t *dip Pointer to the device's dev_info struct
493 * ddi_detach_cmd_t cmd Detach command
494 *
495 * Returns:
496 * DDI_SUCCESS The driver was detached
497 * DDI_FAILURE The driver couldn't be detached
498 */
499 /*ARGSUSED*/
500 static int
conskbd_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)501 conskbd_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
502 {
503 return (DDI_FAILURE);
504
505 } /* conskbd_detach() */
506
507 /* ARGSUSED */
508 static int
conskbd_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)509 conskbd_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
510 void **result)
511 {
512 register int error;
513
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;
521 }
522 break;
523 case DDI_INFO_DEVT2INSTANCE:
524 *result = (void *)0;
525 error = DDI_SUCCESS;
526 break;
527 default:
528 error = DDI_FAILURE;
529 }
530 return (error);
531
532 } /* conskbd_info() */
533
534 /*ARGSUSED*/
535 static int
conskbdopen(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * crp)536 conskbdopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
537 {
538 dev_t unit;
539 int err;
540
541 unit = getminor(*devp);
542
543 if (unit == 0) {
544 /*
545 * Opening "/dev/kbd".
546 */
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);
553 }
554
555 /*
556 * Check if already initialized
557 */
558 if (conskbd_consqueue != NULL)
559 return (0);
560
561 /*
562 * Opening the device to be linked under the console.
563 */
564 conskbd_consqueue = q;
565
566 if (secpolicy_console(crp) != 0)
567 return (EPERM);
568
569 /*
570 * initialize kbtrans module for conskbd
571 */
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);
578
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);
590
591 return (0);
592
593 } /* conskbdopen() */
594
595
596 /*ARGSUSED*/
597 static int
conskbdclose(queue_t * q,int flag,cred_t * crp)598 conskbdclose(queue_t *q, int flag, cred_t *crp)
599 {
600 if (q == conskbd_regqueue) {
601
602 conskbd_pending_msg_t *pmsg, *prev, *next;
603 mblk_t *mp;
604
605 /* switch the input stream back to conskbd_consqueue */
606 conskbd.conskbd_directio = B_FALSE;
607
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;
613
614 /*
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().
619 */
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;
628
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);
634 }
635 mutex_destroy(&pmsg->kpm_lock);
636 kmem_free(pmsg, sizeof (*pmsg));
637 } else {
638 prev = pmsg;
639 }
640 }
641 } else if (q == conskbd_consqueue) {
642 /*
643 * Well, this is probably a mistake, but we will permit you
644 * to close the path to the console if you really insist.
645 */
646 qprocsoff(q);
647 conskbd_consqueue = NULL;
648 }
649
650 return (0);
651
652 } /* conskbdclose() */
653
654 /*
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.
665 */
666 static int
conskbduwsrv(queue_t * q)667 conskbduwsrv(queue_t *q)
668 {
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;
675
676 while ((mp = getq(q)) != NULL) {
677
678 /*
679 * if the virtual keyboard is supported
680 */
681 if (conskbd.conskbd_bypassed == B_FALSE) {
682
683 if (conskbd_override_kbtrans(q, mp) == B_TRUE)
684 continue;
685 /*
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.
706 */
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);
715
716 switch (ret) {
717 case KBTRANS_MESSAGE_HANDLED:
718 continue;
719 case KBTRANS_MESSAGE_NOT_HANDLED:
720 break;
721 }
722 }
723
724 switch (mp->b_datap->db_type) {
725
726 case M_IOCTL:
727 conskbd_ioctl(q, mp);
728 break;
729
730 case M_FLUSH:
731 if (*mp->b_rptr & FLUSHW) {
732 flushq(q, FLUSHDATA);
733 }
734 /*
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.
739 */
740 freemsg(mp);
741 break;
742
743 case M_DATA:
744 /*
745 * virtual keyboard doesn't support this interface.
746 * only when it is disabled, we pass the message
747 * down to lower queue.
748 */
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);
756 }
757 break;
758
759 case M_IOCDATA:
760 /*
761 * Only deal with copyresp to KIOCSETFREQ
762 * transparent ioctl now
763 */
764 csp = (struct copyresp *)mp->b_rptr;
765 if (csp->cp_rval) {
766 miocnak(q, mp, 0, EINVAL);
767 break;
768 }
769
770 error = 0;
771 switch (csp->cp_cmd) {
772 case KIOCSETFREQ:
773 frqp = (struct freq_request *)mp->
774 b_cont->b_rptr;
775
776 switch (frqp->type) {
777 case CONSOLE_BEEP:
778 error = beeper_freq(BEEP_CONSOLE,
779 (int)frqp->freq);
780 break;
781
782 case KBD_BEEP:
783 error = beeper_freq(BEEP_TYPE4,
784 (int)frqp->freq);
785 break;
786
787 default:
788 error = 1;
789 } /* frqp->type */
790
791 break;
792
793 default:
794 error = 1;
795 } /* csp->cp_cmd */
796
797 if (error == 0)
798 miocack(q, mp, 0, 0);
799 else
800 miocnak(q, mp, 0, EINVAL);
801
802 break;
803
804 default:
805 /*
806 * Pass an error message up.
807 */
808 mp->b_datap->db_type = M_ERROR;
809 if (mp->b_cont) {
810 freemsg(mp->b_cont);
811 mp->b_cont = NULL;
812 }
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);
817 }
818 } /* end of while */
819
820 return (0);
821 } /* conskbduwsrv() */
822
823 static void
conskbd_ioctl(queue_t * q,mblk_t * mp)824 conskbd_ioctl(queue_t *q, mblk_t *mp)
825 {
826 struct iocblk *iocp;
827 int error = 0;
828
829 iocp = (struct iocblk *)mp->b_rptr;
830
831 switch (iocp->ioc_cmd) {
832
833 case I_LINK:
834 case I_PLINK:
835 if (conskbd.conskbd_bypassed == B_TRUE) {
836 /*
837 * A legacy keyboard can NOT be connected to conskbd together
838 * with other keyboards. So when a legacy keyboard is already
839 * linked under conkbd, we just reject all others.
840 */
841 miocnak(q, mp, 0, EAGAIN);
842 break;
843 }
844 qwriter(q, mp, conskbd_ioc_plink, PERIM_OUTER);
845 break;
846
847 case I_UNLINK:
848 case I_PUNLINK:
849 qwriter(q, mp, conskbd_ioc_punlink, PERIM_OUTER);
850 break;
851
852 case KIOCSKABORTEN:
853 /*
854 * Check if privileged
855 */
856 if ((error = secpolicy_sys_config(iocp->ioc_cr, B_FALSE))) {
857 miocnak(q, mp, 0, error);
858 return;
859 }
860
861 error = miocpullup(mp, sizeof (int));
862 if (error != 0) {
863 miocnak(q, mp, 0, error);
864 return;
865 }
866
867 abort_enable = *(int *)mp->b_cont->b_rptr;
868 miocack(q, mp, 0, 0);
869 break;
870
871 case KIOCSETFREQ:
872 if (iocp->ioc_count != TRANSPARENT) {
873 /*
874 * We don't support non-transparent ioctls,
875 * i.e. I_STR ioctls
876 */
877 miocnak(q, mp, 0, EINVAL);
878 } else {
879 /* Transparent ioctl */
880 mcopyin(mp, NULL, sizeof (struct freq_request), NULL);
881 qreply(q, mp);
882 }
883 break;
884
885 default:
886 if (conskbd.conskbd_bypassed == B_TRUE) {
887 conskbd_legacy_kbd_ioctl(q, mp);
888 } else {
889 conskbd_virtual_kbd_ioctl(q, mp);
890 }
891 }
892
893 } /* conskbd_ioctl() */
894
895
896 static void
conskbd_virtual_kbd_ioctl(queue_t * q,mblk_t * mp)897 conskbd_virtual_kbd_ioctl(queue_t *q, mblk_t *mp)
898 {
899 struct iocblk *iocp;
900 mblk_t *datap;
901 int cmd;
902 int error = 0;
903
904 iocp = (struct iocblk *)mp->b_rptr;
905
906 switch (iocp->ioc_cmd) {
907 case KIOCLAYOUT:
908 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
909 miocnak(q, mp, 0, ENOMEM);
910 break;
911 }
912
913 if (conskbd.conskbd_layout == -1)
914 *(int *)datap->b_wptr = KBTRANS_USBKB_DEFAULT_LAYOUT;
915 else
916 *(int *)datap->b_wptr = conskbd.conskbd_layout;
917
918 datap->b_wptr += sizeof (int);
919 if (mp->b_cont)
920 freemsg(mp->b_cont);
921 mp->b_cont = datap;
922 miocack(q, mp, sizeof (int), 0);
923 break;
924
925 case KIOCSLAYOUT:
926 if (iocp->ioc_count != TRANSPARENT) {
927 miocnak(q, mp, 0, EINVAL);
928 break;
929 }
930 kbd_layout_bak = conskbd.conskbd_layout;
931 conskbd.conskbd_layout = *(intptr_t *)(mp->b_cont->b_rptr);
932 if (conskbd.conskbd_layout != kbd_layout_bak) {
933
934 /* notify the upper of the change event */
935 if ((datap = conskbd_alloc_firm_event(
936 KEYBOARD_LAYOUT_CHANGE,
937 conskbd.conskbd_layout)) != NULL) {
938 if (conskbd.conskbd_directio) {
939 putnext(conskbd_regqueue, datap);
940 } else {
941 freemsg(datap);
942 }
943 }
944 }
945 miocack(q, mp, 0, 0);
946 break;
947
948 case CONSOPENPOLLEDIO:
949 error = miocpullup(mp, sizeof (struct cons_polledio *));
950 if (error != 0) {
951 miocnak(q, mp, 0, error);
952 break;
953 }
954 if (conskbd.conskbd_lqueue_list == NULL) {
955 miocnak(q, mp, 0, EINVAL);
956 break;
957 }
958 conskbd_handle_downstream_msg(q, mp);
959 break;
960
961 case CONSCLOSEPOLLEDIO:
962 if (conskbd.conskbd_lqueue_list == NULL) {
963 miocnak(q, mp, 0, EINVAL);
964 break;
965 }
966 conskbd_handle_downstream_msg(q, mp);
967 break;
968
969 case CONSSETABORTENABLE:
970 /*
971 * To enable combined STOP-A(or F1-A) to trap into kmdb,
972 * the lower physical keyboard drivers are always told not
973 * to parse abort sequence(refer to consconfig_dacf module).
974 * Instead, lower drivers always send all keydown & keyup
975 * messages up to conskbd, so that when key STOP(or F1) is
976 * pressed on one keyboard and key A is pressed on another
977 * keyboard, the system could trap into kmdb.
978 *
979 * When we by kbtrans_streams_message() invoked kbtrans to
980 * handle ioctls in conskbduwsrv() routine, kbtrans module
981 * already handle the message though it returned to us a
982 * KBTRANS_MESSAGE_NOT_HANDLED. For virtual keyboard, no
983 * special initialization or un-initialization is needed.
984 * So we just return ACK to upper module.
985 */
986 miocack(q, mp, 0, 0);
987 break;
988
989 case KIOCCMD:
990 case KIOCMKTONE:
991 if (conskbd.conskbd_lqueue_list == NULL ||
992 mp->b_cont == NULL) {
993 miocnak(q, mp, 0, EINVAL);
994 break;
995 }
996 cmd = *(int *)mp->b_cont->b_rptr;
997 if (cmd == KBD_CMD_GETLAYOUT) {
998 freemsg(mp->b_cont);
999 datap = allocb(sizeof (int), BPRI_HI);
1000 if (datap == NULL) {
1001 miocnak(q, mp, 0, ENOMEM);
1002 return;
1003 }
1004 if (conskbd.conskbd_layout == -1)
1005 *(int *)datap->b_wptr =
1006 KBTRANS_USBKB_DEFAULT_LAYOUT;
1007 else
1008 *(int *)datap->b_wptr = conskbd.conskbd_layout;
1009
1010 mp->b_cont = datap;
1011 miocack(q, mp, sizeof (int), 0);
1012 return;
1013 }
1014 conskbd_handle_downstream_msg(q, mp);
1015 break;
1016
1017 default:
1018 miocnak(q, mp, 0, EINVAL);
1019 break;
1020 }
1021
1022 } /* conskbd_virtual_kbd_ioctl() */
1023
1024 static void
conskbd_legacy_kbd_ioctl(queue_t * q,mblk_t * mp)1025 conskbd_legacy_kbd_ioctl(queue_t *q, mblk_t *mp)
1026 {
1027 conskbd_lower_queue_t *lq;
1028 struct iocblk *iocp;
1029 int error = 0;
1030
1031 iocp = (struct iocblk *)mp->b_rptr;
1032
1033 ASSERT(conskbd.conskbd_lqueue_nums == 1);
1034 switch (iocp->ioc_cmd) {
1035
1036 case KIOCGDIRECT: {
1037 mblk_t *datap;
1038
1039 if ((datap = allocb(sizeof (int), BPRI_MED)) == NULL) {
1040 miocnak(q, mp, 0, ENOMEM);
1041 break;
1042 }
1043
1044 *(int *)datap->b_wptr = conskbd.conskbd_directio;
1045 datap->b_wptr += sizeof (int);
1046 if (mp->b_cont != NULL) {
1047 freemsg(mp->b_cont);
1048 mp->b_cont = NULL;
1049 }
1050 mp->b_cont = datap;
1051 miocack(q, mp, sizeof (int), 0);
1052 break;
1053 }
1054
1055 case KIOCSDIRECT:
1056 error = miocpullup(mp, sizeof (int));
1057 if (error != 0) {
1058 miocnak(q, mp, 0, error);
1059 break;
1060 }
1061 conskbd.conskbd_directio = *(int *)mp->b_cont->b_rptr;
1062
1063 /*
1064 * Pass this through, if there's something to pass
1065 * it through to, so the system keyboard can reset
1066 * itself.
1067 */
1068 if (conskbd.conskbd_lqueue_nums > 0) {
1069 lq = conskbd.conskbd_lqueue_list;
1070 ASSERT(lq && lq->lqs_next == NULL);
1071 if (putq(lq->lqs_queue, mp) != 1) {
1072 miocnak(q, mp, 0, ENOMEM);
1073 return;
1074 }
1075 break;
1076 }
1077
1078 miocack(q, mp, 0, 0);
1079 break;
1080
1081 default:
1082 /*
1083 * Pass this through, if there's something to pass it
1084 * through to; otherwise, reject it.
1085 */
1086 if (conskbd.conskbd_lqueue_nums > 0) {
1087 lq = conskbd.conskbd_lqueue_list;
1088 ASSERT(lq && lq->lqs_next == NULL);
1089 if (putq(lq->lqs_queue, mp) != 1) {
1090 miocnak(q, mp, 0, ENOMEM);
1091 return;
1092 }
1093 break;
1094 }
1095
1096 /* nobody below us; reject it */
1097 miocnak(q, mp, 0, EINVAL);
1098 break;
1099 }
1100
1101 } /* conskbd_legacy_kbd_ioctl() */
1102
1103
1104 /*
1105 * Service procedure for lower write queue.
1106 * Puts things on the queue below us, if it lets us.
1107 */
1108 static int
conskbdlwserv(queue_t * q)1109 conskbdlwserv(queue_t *q)
1110 {
1111 register mblk_t *mp;
1112
1113 while (canput(q->q_next) && (mp = getq(q)) != NULL)
1114 putnext(q, mp);
1115
1116 return (0);
1117 } /* conskbdlwserv() */
1118
1119 /*
1120 * Put procedure for lower read queue.
1121 * Pass everything up to minor device 0 if "directio" set, otherwise to minor
1122 * device 1.
1123 */
1124 static int
conskbdlrput(queue_t * q,mblk_t * mp)1125 conskbdlrput(queue_t *q, mblk_t *mp)
1126 {
1127 conskbd_lower_queue_t *lqs;
1128 struct iocblk *iocp;
1129 Firm_event *fe;
1130
1131 DPRINTF(PRINT_L1, PRINT_MASK_ALL, ("conskbdlrput\n"));
1132
1133 switch (mp->b_datap->db_type) {
1134 case M_CTL:
1135 mp->b_datap->db_type = M_DATA;
1136 if (conskbd.conskbd_directio)
1137 putnext(conskbd_regqueue, mp);
1138 else if (conskbd_consqueue != NULL)
1139 putnext(conskbd_consqueue, mp);
1140 else
1141 freemsg(mp);
1142 break;
1143
1144 case M_FLUSH:
1145 if (*mp->b_rptr == FLUSHR) {
1146 flushq(q, FLUSHDATA); /* XXX doesn't flush M_DELAY */
1147 *mp->b_rptr &= ~FLUSHR; /* it has been flushed */
1148 }
1149 if (*mp->b_rptr == FLUSHW) {
1150 flushq(WR(q), FLUSHDATA);
1151 qreply(q, mp); /* give the read queues a crack at it */
1152 } else
1153 freemsg(mp);
1154 break;
1155
1156 case M_DATA:
1157 if (conskbd.conskbd_bypassed == B_FALSE) {
1158
1159 fe = (Firm_event *)mp->b_rptr;
1160
1161 /*
1162 * This is a workaround.
1163 *
1164 * According to HID specification, there are the
1165 * following keycode mapping between PS2 and USB,
1166 *
1167 * PS2 AT-101 keycode(29) ---> USB(49)
1168 * PS2 AT-102 keycode(42) ---> USB(50)
1169 *
1170 * However, the two keys, AT-101(29) and AT-102(42),
1171 * have the same scancode,0x2B, in PS2 scancode SET1
1172 * which we are using. The Kb8042 driver always
1173 * recognizes the two keys as PS2(29) so that we could
1174 * not know which is being pressed or released when we
1175 * receive scancode 0x2B. Fortunately, the two keys can
1176 * not co-exist in a specific layout. In other words,
1177 * in the table of keycode-to-symbol mapping, either
1178 * entry 49 or 50 is a hole. So, if we're processing a
1179 * keycode 49, we look at the entry for 49. If it's
1180 * HOLE, remap the key to 50; If we're processing a 50,
1181 * look at the entry for 50. If it's HOLE, we remap
1182 * the key to 49.
1183 */
1184 if (fe->id == 49 || fe->id == 50) {
1185 if (conskbd_keyindex->k_normal[50] == HOLE)
1186 fe->id = 49;
1187 else
1188 fe->id = 50;
1189 }
1190
1191 /*
1192 * Remember key state of each key of lower physical
1193 * keyboard. When a keyboard is umplumbed from conskbd,
1194 * we will check all key states. By then, we will fake
1195 * a KEY_RELEASED message for each key in KEY_PRESSED
1196 * state. Otherwise, upper module will treat these keys
1197 * as held-down for ever.
1198 */
1199 iocp = (struct iocblk *)mp->b_rptr;
1200 lqs = (conskbd_lower_queue_t *)q->q_ptr;
1201 if (fe->value)
1202 lqs->lqs_key_state[fe->id] = KEY_PRESSED;
1203 else
1204 lqs->lqs_key_state[fe->id] = KEY_RELEASED;
1205
1206 kbtrans_streams_key(conskbd.conskbd_kbtrans,
1207 fe->id, fe->value ? KEY_PRESSED : KEY_RELEASED);
1208 freemsg(mp);
1209 } else {
1210 if (conskbd.conskbd_directio)
1211 putnext(conskbd_regqueue, mp);
1212 else if (conskbd_consqueue != NULL)
1213 putnext(conskbd_consqueue, mp);
1214 else
1215 freemsg(mp);
1216 }
1217 conskbd_idle_stamp = gethrestime_sec();
1218 break;
1219
1220 case M_IOCACK:
1221 case M_IOCNAK:
1222 iocp = (struct iocblk *)mp->b_rptr;
1223 lqs = (conskbd_lower_queue_t *)q->q_ptr;
1224
1225 DPRINTF(PRINT_L1, PRINT_MASK_ALL, ("conskbdlrput: "
1226 "ACK/NAK - cmd 0x%x\n", iocp->ioc_cmd));
1227
1228 conskbd_lqs_ack_complete(lqs, mp);
1229 break;
1230
1231 case M_ERROR:
1232 case M_HANGUP:
1233 default:
1234 freemsg(mp); /* anything useful here? */
1235 break;
1236 }
1237
1238 return (0);
1239 } /* conskbdlrput() */
1240
1241
1242 /* ARGSUSED */
1243 static int
conskbd_kstat_update(kstat_t * ksp,int rw)1244 conskbd_kstat_update(kstat_t *ksp, int rw)
1245 {
1246 if (rw == KSTAT_WRITE)
1247 return (EACCES);
1248
1249 conskbd_kstat.idle_sec.value.l = gethrestime_sec() - conskbd_idle_stamp;
1250
1251 return (0);
1252
1253 } /* conskbd_kstat_update() */
1254
1255 /*
1256 * STREAMS architecuture provides guarantee that the ID of each
1257 * message, iocblk.ioc_id, in a stream is unique. The following
1258 * routine performes the task: When receive request from upstream,
1259 * it saves the request in a global link list, clones the request,
1260 * and then sends a copy of the request to each of lower queues
1261 * which are plumbed into conskbd. And then, when receives responses
1262 * from lower queues in conskbdlrput() routine, we can know the
1263 * request matching received responses by searching the global linked
1264 * list to find the request which has the same message ID of the
1265 * response. Then, when all lower queues response this request, we
1266 * give a response to upstreams based the following policy:
1267 * If any one of lower queues acks our reuqest, then we return ack
1268 * to upstreams; only if all lower queues nak our request, we return
1269 * nak to upstreams. If all responses are nak, the error number of
1270 * the first response is sent to upstream.
1271 */
1272 static void
conskbd_handle_downstream_msg(queue_t * q,mblk_t * mp)1273 conskbd_handle_downstream_msg(queue_t *q, mblk_t *mp)
1274 {
1275 conskbd_pending_msg_t *msg;
1276 conskbd_lower_queue_t *lqs;
1277 struct iocblk *iocp;
1278 mblk_t *clonemp;
1279 int retry;
1280
1281 if (conskbd.conskbd_lqueue_nums == 0) {
1282 miocnak(q, mp, 0, EINVAL);
1283 return;
1284 }
1285
1286 msg = (conskbd_pending_msg_t *)
1287 kmem_zalloc(sizeof (conskbd_pending_msg_t), KM_SLEEP);
1288 mutex_init(&msg->kpm_lock, NULL, MUTEX_DRIVER, NULL);
1289 lqs = conskbd.conskbd_lqueue_list;
1290 iocp = (struct iocblk *)mp->b_rptr;
1291
1292 ASSERT(iocp->ioc_cmd == CONSOPENPOLLEDIO ||
1293 iocp->ioc_cmd == CONSCLOSEPOLLEDIO ||
1294 iocp->ioc_cmd == KIOCCMD ||
1295 iocp->ioc_cmd == KIOCMKTONE);
1296
1297 msg->kpm_upper_queue = q;
1298 msg->kpm_req_msg = mp;
1299 msg->kpm_req_id = iocp->ioc_id;
1300 msg->kpm_req_cmd = iocp->ioc_cmd;
1301 msg->kpm_req_nums = conskbd.conskbd_lqueue_nums;
1302 conskbd_mux_enqueue_msg(msg);
1303
1304 for (retry = 0, lqs = conskbd.conskbd_lqueue_list; lqs; ) {
1305
1306 /*
1307 * if a lower physical keyboard is not in polled I/O
1308 * mode, we couldn't send CONSCLOSEPOLLEDIO to it,
1309 * otherwise, system will panic.
1310 */
1311 if (iocp->ioc_cmd == CONSCLOSEPOLLEDIO &&
1312 lqs->lqs_polledio == NULL) {
1313 lqs = lqs->lqs_next;
1314 msg->kpm_req_nums --;
1315 retry = 0;
1316 continue;
1317 }
1318
1319 clonemp = copymsg(mp);
1320 if (clonemp != NULL) {
1321 if (putq(lqs->lqs_queue, clonemp) == 1) {
1322 lqs = lqs->lqs_next;
1323 retry = 0;
1324 continue;
1325 }
1326
1327 /*
1328 * failed to invoke putq(), retry.
1329 */
1330 freemsg(clonemp);
1331 }
1332
1333 /*
1334 * During testing it was observed that occasionally
1335 * copymsg() would fail during boot. The reason for
1336 * these failures is unknown. Since we really want
1337 * to successfully plumb up all the attached keyboards
1338 * during boot we do a best effort here by retrying
1339 * the copymsg() call in the hopes that it will
1340 * succeeded upon subsequent invocations.
1341 *
1342 * If all the calls to copymsg() fails, it will cause
1343 * the corresponding keyboard to be unavailable, or
1344 * or behave weirdly,
1345 *
1346 * 1) for CONSOPENPOLLEDIO
1347 * if copymsg()fails, the corresponding keyboard
1348 * is not available in polled I/O mode once
1349 * entering kmdb;
1350 * 2) for CONSCLOSEPOLLEDIO
1351 * if copymsg() fails, the corresponding keyboard
1352 * is not available in normal mode once returning
1353 * from kmdb;
1354 * 3) for KIOCCMD
1355 * 3.1) for KBD_CMD_NOBELL
1356 * there's no beep in USB and PS2 keyboard,
1357 * this ioctl actually disables the beep on
1358 * system mainboard. Note that all the cloned
1359 * messages sent down to lower queues do the
1360 * same job for system mainboard. Therefore,
1361 * even if we fail to send this ioctl to most
1362 * of lower queues, the beep still would be
1363 * disabled. So, no trouble exists here.
1364 * 3.2) for others
1365 * nothing;
1366 *
1367 * However, all cases could be resume next time when the
1368 * same request comes again.
1369 */
1370 if (retry ++ >= 5) {
1371 dev_t devt;
1372 char path[MAXPATHLEN + 1];
1373
1374 devt = lqs->lqs_queue->q_stream->sd_vnode->v_rdev;
1375 switch (iocp->ioc_cmd) {
1376 case CONSOPENPOLLEDIO:
1377 if (ddi_dev_pathname(devt, S_IFCHR,
1378 path) == DDI_SUCCESS)
1379 cmn_err(CE_WARN, "conskbd: "
1380 "keyboard is not available"
1381 " for system debugging: %s",
1382 path);
1383 break;
1384
1385 case CONSCLOSEPOLLEDIO:
1386 if (ddi_dev_pathname(devt, S_IFCHR,
1387 path) == DDI_SUCCESS)
1388 cmn_err(CE_WARN, "conskbd: "
1389 "keyboard is not available:"
1390 " %s", path);
1391 break;
1392
1393 default:
1394 break;
1395 }
1396 msg->kpm_req_nums --;
1397 lqs = lqs->lqs_next;
1398 retry = 0;
1399 }
1400 }
1401
1402 if (msg->kpm_req_nums == 0) {
1403 conskbd_mux_dequeue_msg(msg);
1404 kmem_free(msg, sizeof (*msg));
1405 miocnak(q, mp, 0, ENOMEM);
1406 }
1407
1408 } /* conskbd_handle_downstream_msg() */
1409
1410
1411 static void
conskbd_ioc_plink(queue_t * q,mblk_t * mp)1412 conskbd_ioc_plink(queue_t *q, mblk_t *mp)
1413 {
1414 mblk_t *req;
1415 queue_t *lowque;
1416 struct linkblk *linkp;
1417 conskbd_lower_queue_t *lqs;
1418
1419 lqs = kmem_zalloc(sizeof (*lqs), KM_SLEEP);
1420 ASSERT(lqs->lqs_state == LQS_UNINITIALIZED);
1421
1422 linkp = (struct linkblk *)mp->b_cont->b_rptr;
1423 lowque = linkp->l_qbot;
1424
1425 lqs->lqs_queue = lowque;
1426 lqs->lqs_pending_plink = mp;
1427 lqs->lqs_pending_queue = q;
1428
1429 req = mkiocb(CONSSETKBDTYPE);
1430 if (req == NULL) {
1431 miocnak(q, mp, 0, ENOMEM);
1432 kmem_free(lqs, sizeof (*lqs));
1433 return;
1434 }
1435
1436 req->b_cont = allocb(sizeof (int), BPRI_MED);
1437 if (req->b_cont == NULL) {
1438 freemsg(req);
1439 miocnak(q, mp, 0, ENOMEM);
1440 kmem_free(lqs, sizeof (*lqs));
1441 return;
1442 }
1443
1444 lowque->q_ptr = lqs;
1445 OTHERQ(lowque)->q_ptr = lqs;
1446 *(int *)req->b_cont->b_wptr = KB_USB;
1447 req->b_cont->b_wptr += sizeof (int);
1448
1449 lqs->lqs_state = LQS_KIOCTYPE_ACK_PENDING;
1450
1451 if (putq(lowque, req) != 1) {
1452 freemsg(req);
1453 miocnak(lqs->lqs_pending_queue,
1454 lqs->lqs_pending_plink, 0, ENOMEM);
1455 lowque->q_ptr = NULL;
1456 OTHERQ(lowque)->q_ptr = NULL;
1457 kmem_free(lqs, sizeof (*lqs));
1458 }
1459
1460 } /* conskbd_ioc_plink() */
1461
1462
1463 static void
conskbd_ioc_punlink(queue_t * q,mblk_t * mp)1464 conskbd_ioc_punlink(queue_t *q, mblk_t *mp)
1465 {
1466 int index;
1467 struct linkblk *linkp;
1468 conskbd_lower_queue_t *lqs;
1469 conskbd_lower_queue_t *prev;
1470
1471 linkp = (struct linkblk *)mp->b_cont->b_rptr;
1472 prev = conskbd.conskbd_lqueue_list;
1473 for (lqs = prev; lqs; lqs = lqs->lqs_next) {
1474 if (lqs->lqs_queue == linkp->l_qbot) {
1475 if (prev == lqs)
1476 conskbd.conskbd_lqueue_list =
1477 lqs->lqs_next;
1478 else
1479 prev->lqs_next = lqs->lqs_next;
1480
1481 lqs->lqs_queue->q_ptr = NULL;
1482 OTHERQ(lqs->lqs_queue)->q_ptr = NULL;
1483 conskbd.conskbd_lqueue_nums --;
1484 if (conskbd.conskbd_lqueue_nums == 0) {
1485 kbd_layout_bak = conskbd.conskbd_layout;
1486 conskbd.conskbd_layout = -1;
1487 }
1488
1489 for (index = 0; index < KBTRANS_KEYNUMS_MAX; index ++) {
1490 if (lqs->lqs_key_state[index] == KEY_PRESSED)
1491 kbtrans_streams_key(
1492 conskbd.conskbd_kbtrans,
1493 index,
1494 KEY_RELEASED);
1495 }
1496
1497 kmem_free(lqs, sizeof (*lqs));
1498 miocack(q, mp, 0, 0);
1499 return;
1500 }
1501 prev = lqs;
1502 }
1503 miocnak(q, mp, 0, EINVAL);
1504
1505 } /* conskbd_ioc_punlink() */
1506
1507 /*
1508 * Every physical keyboard has a corresponding STREAMS queue. We call this
1509 * queue lower queue. Every lower queue has a state, refer to conskbd.h file
1510 * about "enum conskbd_lqs_state".
1511 * The following routine is used to handle response messages from lower queue.
1512 * When receiving ack/nak message from lower queue(s), the routine determines
1513 * the passage for it according to the current state of this lower queue.
1514 */
1515 static void
conskbd_lqs_ack_complete(conskbd_lower_queue_t * lqs,mblk_t * mp)1516 conskbd_lqs_ack_complete(conskbd_lower_queue_t *lqs, mblk_t *mp)
1517 {
1518 switch (lqs->lqs_state) {
1519
1520 /* S6: working in virtual keyboard mode, multi-keyboards are usable */
1521 case LQS_INITIALIZED:
1522 conskbd_mux_upstream_msg(lqs, mp);
1523 break;
1524
1525 /* S5: working in legacy mode, only one keyboard is usable */
1526 case LQS_INITIALIZED_LEGACY:
1527 conskbd_legacy_upstream_msg(lqs, mp);
1528 break;
1529
1530 /* S4: wait lower queue to acknowledge KIOCSLED/KIOCGLED message */
1531 case LQS_KIOCSLED_ACK_PENDING:
1532 conskbd_kiocsled_complete(lqs, mp);
1533 break;
1534
1535 /* S3: wait lower queue to acknowledge KIOCLAYOUT message */
1536 case LQS_KIOCLAYOUT_ACK_PENDING:
1537 conskbd_kioclayout_complete(lqs, mp);
1538 break;
1539
1540 /* S2: wait lower queue to acknowledge KIOCTRANS message */
1541 case LQS_KIOCTRANS_ACK_PENDING:
1542 conskbd_kioctrans_complete(lqs, mp);
1543 break;
1544
1545 /* S1: wait lower queue to acknowledge KIOCTYPE message */
1546 case LQS_KIOCTYPE_ACK_PENDING:
1547 conskbd_kioctype_complete(lqs, mp);
1548 break;
1549
1550 /* if reaching here, there must be a error */
1551 default:
1552 freemsg(mp);
1553 cmn_err(CE_WARN, "conskbd: lqs_ack_complete() state error");
1554 break;
1555 }
1556
1557 } /* conskbd_lqs_ack_complete() */
1558
1559
1560 static void
conskbd_kioctype_complete(conskbd_lower_queue_t * lqs,mblk_t * mp)1561 conskbd_kioctype_complete(conskbd_lower_queue_t *lqs, mblk_t *mp)
1562 {
1563 struct iocblk *iocp;
1564 mblk_t *req;
1565 queue_t *lowerque;
1566 int err = ENOMEM;
1567
1568 ASSERT(lqs->lqs_pending_plink);
1569 ASSERT(lqs->lqs_state == LQS_KIOCTYPE_ACK_PENDING);
1570
1571 lowerque = lqs->lqs_queue;
1572
1573 switch (mp->b_datap->db_type) {
1574 case M_IOCACK:
1575 req = mkiocb(KIOCTRANS);
1576 if (req == NULL) {
1577 goto err_exit;
1578 }
1579
1580 req->b_cont = allocb(sizeof (int), BPRI_MED);
1581 if (req->b_cont == NULL) {
1582 freemsg(req);
1583 goto err_exit;
1584 }
1585
1586 /* Set the translate mode to TR_UNTRANS_EVENT */
1587 *(int *)req->b_cont->b_wptr = TR_UNTRANS_EVENT;
1588 req->b_cont->b_wptr += sizeof (int);
1589
1590 /* Ready to handle the response to KIOCTRANS */
1591 lqs->lqs_state = LQS_KIOCTRANS_ACK_PENDING;
1592
1593 if (putq(lowerque, req) != 1) {
1594 freemsg(req);
1595 goto err_exit;
1596 }
1597 freemsg(mp);
1598 return;
1599
1600 case M_IOCNAK:
1601 /*
1602 * The lower keyboard driver can't mimic USB keyboard,
1603 * that's say, the physical keyboard is an old one, such
1604 * as TYPE 3/4/5 one. In this case, the virtual keyboard
1605 * is disabled, and the data from lower keyboard driver
1606 * will bypass the conskbd module.
1607 */
1608
1609 /*
1610 * if there is any other keyborad already linked under the
1611 * conskbd, we reject the current one.
1612 */
1613 if (conskbd.conskbd_lqueue_nums > 0) {
1614 iocp = (struct iocblk *)mp->b_rptr;
1615 err = iocp->ioc_error;
1616 goto err_exit;
1617 }
1618
1619 /*
1620 * link this keyboard under conskbd.
1621 */
1622 qwriter(lowerque, mp, conskbd_link_lowque_legacy, PERIM_OUTER);
1623 return;
1624 }
1625
1626 err_exit:
1627 miocnak(lqs->lqs_pending_queue, lqs->lqs_pending_plink, 0, err);
1628 lowerque->q_ptr = NULL;
1629 OTHERQ(lowerque)->q_ptr = NULL;
1630 kmem_free(lqs, sizeof (*lqs));
1631 freemsg(mp);
1632
1633 } /* conskbd_kioctype_complete() */
1634
1635 static void
conskbd_kioctrans_complete(conskbd_lower_queue_t * lqs,mblk_t * mp)1636 conskbd_kioctrans_complete(conskbd_lower_queue_t *lqs, mblk_t *mp)
1637 {
1638 struct iocblk *iocp;
1639 mblk_t *req;
1640 queue_t *lowerque;
1641 int err = ENOMEM;
1642
1643 ASSERT(lqs->lqs_pending_plink != NULL);
1644 ASSERT(lqs->lqs_state == LQS_KIOCTRANS_ACK_PENDING);
1645
1646 lowerque = lqs->lqs_queue;
1647
1648 switch (mp->b_datap->db_type) {
1649 case M_IOCACK:
1650 req = mkiocb(KIOCLAYOUT);
1651 if (req == NULL) {
1652 goto err_exit;
1653 }
1654
1655 req->b_cont = allocb(sizeof (int), BPRI_MED);
1656 if (req->b_cont == NULL) {
1657 freemsg(req);
1658 goto err_exit;
1659 }
1660
1661 /* waiting for response to KIOCLAYOUT */
1662 lqs->lqs_state = LQS_KIOCLAYOUT_ACK_PENDING;
1663 if (putq(lqs->lqs_queue, req) != 1) {
1664 freemsg(req);
1665 goto err_exit;
1666 }
1667 freemsg(mp);
1668 return;
1669
1670 case M_IOCNAK:
1671 iocp = (struct iocblk *)mp->b_rptr;
1672 err = iocp->ioc_error;
1673 goto err_exit;
1674 }
1675
1676 err_exit:
1677 miocnak(lqs->lqs_pending_queue, lqs->lqs_pending_plink, 0, err);
1678 lowerque->q_ptr = NULL;
1679 OTHERQ(lowerque)->q_ptr = NULL;
1680 kmem_free(lqs, sizeof (*lqs));
1681 freemsg(mp);
1682
1683 } /* conskbd_kioctrans_complete() */
1684
1685 /*
1686 * Allocate a firm event
1687 */
1688 static mblk_t *
conskbd_alloc_firm_event(ushort_t id,int value)1689 conskbd_alloc_firm_event(ushort_t id, int value)
1690 {
1691 mblk_t *mb;
1692 Firm_event *fe;
1693
1694 if ((mb = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
1695 fe = (Firm_event *)mb->b_wptr;
1696 fe->id = id;
1697 fe->pair_type = FE_PAIR_NONE;
1698 fe->pair = '\0';
1699 fe->value = value;
1700 mb->b_wptr += sizeof (Firm_event);
1701 }
1702
1703 return (mb);
1704 }
1705
1706 static void
conskbd_kioclayout_complete(conskbd_lower_queue_t * lqs,mblk_t * mp)1707 conskbd_kioclayout_complete(conskbd_lower_queue_t *lqs, mblk_t *mp)
1708 {
1709 mblk_t *req;
1710 int layout;
1711 boolean_t fail;
1712
1713 ASSERT(lqs->lqs_pending_plink != NULL);
1714 ASSERT(lqs->lqs_state == LQS_KIOCLAYOUT_ACK_PENDING);
1715
1716 switch (mp->b_datap->db_type) {
1717 case M_IOCACK:
1718 if (miocpullup(mp, sizeof (int)) == 0) {
1719 layout = *(int *)mp->b_cont->b_rptr;
1720 /*
1721 * We just accept the layout of the first keyboard
1722 * requesting to be linked under conskbd. If current
1723 * keyboard is the first one, and if we get right
1724 * layout from it, we set conskbd's layout
1725 */
1726 if (layout != -1 && conskbd.conskbd_layout == -1) {
1727 if (layout == 0) {
1728 conskbd.conskbd_layout = kbd_layout_bak;
1729 } else {
1730 conskbd.conskbd_layout = layout;
1731 if (layout == kbd_layout_bak) {
1732 break;
1733 }
1734 if ((req = conskbd_alloc_firm_event(
1735 KEYBOARD_LAYOUT_CHANGE,
1736 layout)) != NULL) {
1737 if (conskbd.conskbd_directio) {
1738 putnext(
1739 conskbd_regqueue,
1740 req);
1741 } else if (conskbd_consqueue
1742 != NULL) {
1743 putnext(
1744 conskbd_consqueue,
1745 req);
1746 } else {
1747 freemsg(req);
1748 }
1749 }
1750 }
1751 }
1752 }
1753 break;
1754
1755
1756 /* if fail, leave conskbd's layout as it is */
1757 case M_IOCNAK:
1758 break;
1759 }
1760
1761 fail = B_TRUE;
1762
1763 if (conskbd.conskbd_led_state == -1)
1764 req = mkiocb(KIOCGLED);
1765 else
1766 req = mkiocb(KIOCSLED);
1767
1768 if (req) {
1769 req->b_cont = allocb(sizeof (uchar_t), BPRI_MED);
1770 if (req->b_cont) {
1771 if (conskbd.conskbd_led_state != -1) {
1772 *(uchar_t *)req->b_cont->b_wptr =
1773 conskbd.conskbd_led_state;
1774 req->b_cont->b_wptr += sizeof (uchar_t);
1775 }
1776
1777 /* waiting for response to KIOCSLED */
1778 lqs->lqs_state = LQS_KIOCSLED_ACK_PENDING;
1779 if (putq(lqs->lqs_queue, req) == 1) {
1780 fail = B_FALSE;
1781 } else {
1782 freemsg(req);
1783 }
1784
1785 } else {
1786 freemsg(req);
1787 }
1788 }
1789
1790 if (fail) {
1791 /*
1792 * If fail to allocate KIOCSLED/KIOCGLED message or put
1793 * the message into lower queue, we immediately link
1794 * current keyboard under conskbd. Thus, even if fails
1795 * to set/get LED, this keyboard could be available.
1796 */
1797 qwriter(lqs->lqs_queue,
1798 mp, conskbd_link_lowque_virt, PERIM_OUTER);
1799 } else {
1800 freemsg(mp);
1801 }
1802
1803 } /* conskbd_kioclayout_complete() */
1804
1805
1806 static void
conskbd_kiocsled_complete(conskbd_lower_queue_t * lqs,mblk_t * mp)1807 conskbd_kiocsled_complete(conskbd_lower_queue_t *lqs, mblk_t *mp)
1808 {
1809 int led_state;
1810
1811 ASSERT(lqs->lqs_pending_plink != NULL);
1812 ASSERT(lqs->lqs_state == LQS_KIOCSLED_ACK_PENDING);
1813
1814 if (conskbd.conskbd_led_state == -1) {
1815 switch (mp->b_datap->db_type) {
1816 case M_IOCACK:
1817 if (miocpullup(mp, sizeof (uchar_t)) == 0) {
1818 led_state = *(uchar_t *)mp->b_cont->b_rptr;
1819 conskbd.conskbd_led_state = led_state;
1820 kbtrans_streams_setled(conskbd.conskbd_kbtrans,
1821 led_state);
1822 }
1823 break;
1824
1825 /* if fail, leave conskbd's led_state as it is */
1826 case M_IOCNAK:
1827 break;
1828 }
1829 }
1830
1831 /*
1832 * Basically, failure of setting/getting LED is not a fatal
1833 * error, so we will plumb the lower queue into conskbd whether
1834 * setting/getting LED succeeds or fails.
1835 */
1836 qwriter(lqs->lqs_queue, mp, conskbd_link_lowque_virt, PERIM_OUTER);
1837
1838 } /* conskbd_kiocsled_complete() */
1839
1840
1841 static void
conskbd_mux_upstream_msg(conskbd_lower_queue_t * lqs,mblk_t * mp)1842 conskbd_mux_upstream_msg(conskbd_lower_queue_t *lqs, mblk_t *mp)
1843 {
1844 conskbd_pending_msg_t *msg;
1845 struct iocblk *iocp;
1846 int error;
1847 dev_t devt;
1848 char path[MAXPATHLEN + 1];
1849
1850 ASSERT(lqs->lqs_state == LQS_INITIALIZED);
1851 msg = conskbd_mux_find_msg(mp);
1852
1853 if (!msg) {
1854 /*
1855 * Here we discard the response if:
1856 *
1857 * 1. It's an KIOCSLED request; see conskbd_streams_setled().
1858 * 2. The application has already closed the upper stream;
1859 * see conskbdclose()
1860 */
1861 freemsg(mp);
1862 return;
1863 }
1864
1865 /*
1866 * We use the b_next field of mblk_t structure to link all
1867 * response coming from lower queues into a linkage list,
1868 * and make use of the b_prev field to save a pointer to
1869 * the lower queue from which the current response message
1870 * comes.
1871 */
1872 ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
1873 mutex_enter(&msg->kpm_lock);
1874 mp->b_next = msg->kpm_resp_list;
1875 mp->b_prev = (mblk_t *)lqs;
1876 msg->kpm_resp_list = mp;
1877 msg->kpm_resp_nums ++;
1878
1879 if (msg->kpm_resp_nums < msg->kpm_req_nums) {
1880 mutex_exit(&msg->kpm_lock);
1881 return;
1882 }
1883
1884 ASSERT(msg->kpm_resp_nums == msg->kpm_req_nums);
1885 ASSERT(mp == msg->kpm_resp_list);
1886
1887 mutex_exit(&msg->kpm_lock);
1888
1889 conskbd_mux_dequeue_msg(msg);
1890
1891
1892 /*
1893 * Here, we have the policy that, if any one lower queue ACK
1894 * our reuqest, then we return ACK to upstreams; only if all
1895 * lower queues NAK our request, we return NAK to upstreams.
1896 * if all responses are nak, the errno of the first response
1897 * is sent to upstreams
1898 */
1899 ASSERT(mp->b_rptr);
1900 error = ((struct iocblk *)mp->b_rptr)->ioc_error;
1901
1902 switch (msg->kpm_req_cmd) {
1903 case CONSOPENPOLLEDIO:
1904 /*
1905 * Here, we can safely ignore the NAK message. If any one lower
1906 * queue returns NAK, the pointer to the corresponding polledio
1907 * structure will remain null, that's say lqs->lqs_polledio =
1908 * null. When we need to invoke polled I/O interface, we will
1909 * check if the pointer is null.
1910 */
1911 for (mp = msg->kpm_resp_list; mp; ) {
1912 cons_polledio_t *polledio;
1913
1914 msg->kpm_resp_list = mp->b_next;
1915 lqs = (conskbd_lower_queue_t *)mp->b_prev;
1916 devt = lqs->lqs_queue->q_stream->sd_vnode->v_rdev;
1917 if (mp->b_datap->db_type == M_IOCACK) {
1918 polledio = *(struct cons_polledio **)
1919 mp->b_cont->b_rptr;
1920 if (polledio->cons_polledio_version ==
1921 CONSPOLLEDIO_V1) {
1922 lqs->lqs_polledio = polledio;
1923 error = 0;
1924 } else {
1925 /*
1926 * USB and PS2 keyboard drivers should
1927 * use the same cons_polledio structure
1928 * as conskbd.
1929 */
1930 if (ddi_dev_pathname(devt, S_IFCHR,
1931 path) == DDI_SUCCESS) {
1932 cmn_err(CE_WARN, "keyboard "
1933 "driver does not support "
1934 "system debugging: %s",
1935 path);
1936 }
1937 error = EINVAL;
1938 }
1939 } else {
1940 if (ddi_dev_pathname(devt, S_IFCHR, path) ==
1941 DDI_SUCCESS) {
1942 cmn_err(CE_WARN, "conskbd: keyboard is"
1943 " not available for system"
1944 " debugging: %s", path);
1945 }
1946 }
1947 mp->b_next = NULL;
1948 mp->b_prev = NULL;
1949 freemsg(mp);
1950 mp = msg->kpm_resp_list;
1951 }
1952
1953 mp = msg->kpm_req_msg;
1954 if (error == 0) {
1955 *(struct cons_polledio **)mp->b_cont->b_rptr =
1956 &conskbd.conskbd_polledio;
1957 }
1958 break;
1959
1960 case CONSCLOSEPOLLEDIO:
1961 for (mp = msg->kpm_resp_list; mp; ) {
1962 msg->kpm_resp_list = mp->b_next;
1963 lqs = (conskbd_lower_queue_t *)mp->b_prev;
1964 if (mp->b_datap->db_type == M_IOCACK) {
1965 lqs->lqs_polledio = NULL;
1966 error = 0;
1967 } else {
1968 devt =
1969 lqs->lqs_queue->q_stream->sd_vnode->v_rdev;
1970
1971 if (ddi_dev_pathname(devt, S_IFCHR, path) ==
1972 DDI_SUCCESS) {
1973 cmn_err(CE_WARN, "conskbd: keyboard is"
1974 " not available: %s", path);
1975 }
1976 }
1977
1978 mp->b_next = NULL;
1979 mp->b_prev = NULL;
1980 freemsg(mp);
1981 mp = msg->kpm_resp_list;
1982 }
1983 break;
1984
1985 case KIOCCMD:
1986 case KIOCMKTONE:
1987 for (mp = msg->kpm_resp_list; mp; ) {
1988 msg->kpm_resp_list = mp->b_next;
1989
1990 if (mp->b_datap->db_type == M_IOCACK)
1991 error = 0;
1992 mp->b_next = NULL;
1993 mp->b_prev = NULL;
1994 freemsg(mp);
1995 mp = msg->kpm_resp_list;
1996 }
1997 break;
1998
1999 default: /* it is impossible to reach here */
2000 cmn_err(CE_WARN, "conskbd: unexpected ioctl reply");
2001 }
2002
2003 mp = msg->kpm_req_msg;
2004 if (error == 0) {
2005 mp->b_datap->db_type = M_IOCACK;
2006 } else {
2007 mp->b_datap->db_type = M_IOCNAK;
2008 }
2009 iocp = (struct iocblk *)mp->b_rptr;
2010 iocp->ioc_error = error;
2011 qreply(msg->kpm_upper_queue, mp);
2012 mutex_destroy(&msg->kpm_lock);
2013 kmem_free(msg, sizeof (*msg));
2014
2015 } /* conskbd_mux_upstream_msg() */
2016
2017 static void
conskbd_link_lowque_legacy(queue_t * lowque,mblk_t * mp)2018 conskbd_link_lowque_legacy(queue_t *lowque, mblk_t *mp)
2019 {
2020 conskbd_lower_queue_t *lqs;
2021
2022 freemsg(mp);
2023
2024 /*
2025 * Bypass the virutal keyboard for old hardware,
2026 * Now, only current legacy keyboard can be linked
2027 * under conskbd
2028 */
2029 conskbd.conskbd_bypassed = B_TRUE;
2030
2031 /*
2032 * Link the lower queue under conskbd
2033 */
2034 lqs = (conskbd_lower_queue_t *)lowque->q_ptr;
2035 lqs->lqs_state = LQS_INITIALIZED_LEGACY;
2036 lqs->lqs_next = conskbd.conskbd_lqueue_list;
2037 conskbd.conskbd_lqueue_list = lqs;
2038 conskbd.conskbd_lqueue_nums++;
2039
2040 mioc2ack(lqs->lqs_pending_plink, NULL, 0, 0);
2041 qreply(lqs->lqs_pending_queue, lqs->lqs_pending_plink);
2042
2043 } /* conskbd_link_lowque_legacy() */
2044
2045 static void
conskbd_link_lowque_virt(queue_t * lowque,mblk_t * mp)2046 conskbd_link_lowque_virt(queue_t *lowque, mblk_t *mp)
2047 {
2048 int index;
2049 conskbd_lower_queue_t *lqs;
2050
2051 freemsg(mp);
2052
2053 lqs = (conskbd_lower_queue_t *)lowque->q_ptr;
2054
2055 ASSERT(lqs->lqs_queue == lowque);
2056 ASSERT(lqs->lqs_pending_plink != NULL);
2057
2058 /*
2059 * Now, link the lower queue under conskbd
2060 */
2061 for (index = 0; index < KBTRANS_KEYNUMS_MAX; index ++) {
2062 lqs->lqs_key_state[index] = KEY_RELEASED;
2063 }
2064 lqs->lqs_next = conskbd.conskbd_lqueue_list;
2065 lqs->lqs_state = LQS_INITIALIZED;
2066 conskbd.conskbd_lqueue_nums++;
2067 conskbd.conskbd_lqueue_list = lqs;
2068 mioc2ack(lqs->lqs_pending_plink, NULL, 0, 0);
2069 qreply(lqs->lqs_pending_queue, lqs->lqs_pending_plink);
2070
2071 } /* conskbd_link_lowque_virt() */
2072
2073 /*ARGSUSED*/
2074 static void
conskbd_legacy_upstream_msg(conskbd_lower_queue_t * lqs,mblk_t * mp)2075 conskbd_legacy_upstream_msg(conskbd_lower_queue_t *lqs, mblk_t *mp)
2076 {
2077 struct iocblk *iocp;
2078
2079 ASSERT(lqs && lqs->lqs_state == LQS_INITIALIZED_LEGACY);
2080
2081 /*
2082 * We assume that all of the ioctls are headed to the
2083 * conskbd_regqueue if it is open. We are intercepting a few ioctls
2084 * that we know belong to conskbd_consqueue, and sending them there.
2085 * Any other, new ioctls that have to be routed to conskbd_consqueue
2086 * should be added to this list.
2087 */
2088 iocp = (struct iocblk *)mp->b_rptr;
2089
2090 if ((iocp->ioc_cmd == CONSOPENPOLLEDIO) ||
2091 (iocp->ioc_cmd == CONSCLOSEPOLLEDIO)) {
2092
2093 DPRINTF(PRINT_L1, PRINT_MASK_ALL,
2094 ("conskbd_legacy_upstream_msg: "
2095 "CONSOPEN/CLOSEPOLLEDIO ACK/NAK\n"));
2096 putnext(conskbd_consqueue, mp);
2097
2098 } else if (conskbd_regqueue != NULL) {
2099 DPRINTF(PRINT_L1, PRINT_MASK_ALL,
2100 ("conskbd_legacy_upstream_msg: conskbd_regqueue != NULL"));
2101
2102 putnext(conskbd_regqueue, mp);
2103
2104 } else if (conskbd_consqueue != NULL) {
2105 DPRINTF(PRINT_L1, PRINT_MASK_ALL,
2106 ("conskbd_legacy_upstream_msg: conskbd_consqueue != NULL"));
2107 putnext(conskbd_consqueue, mp);
2108 } else {
2109 /* if reached here, it must be a error */
2110 cmn_err(CE_WARN,
2111 "kb: no destination for IOCACK/IOCNAK!");
2112 freemsg(mp);
2113 }
2114
2115 } /* conskbd_legacy_upstream_msg() */
2116
2117 /*
2118 * This routine is a callback routine for kbtrans module to set LED.
2119 * Kbtrans will invoke it in two cases:
2120 *
2121 * 1) application initiated request
2122 * A KIOCSLED ioctl is sent by an application. The ioctl will be
2123 * be prcoessed by queue service procedure conskbduwsrv(), which
2124 * in turn calls kbtrans to process the ioctl. Then kbtrans invokes
2125 * conskbd_streams_setled() to set LED, after that, kbtrans will
2126 * return an ACK message to upper module.
2127 *
2128 * 2) Kbtrans initiated the request
2129 * When conskbd works in TR_ASCII translation mode, if anyone of
2130 * CapsLock, NumberLock and Compose keys is pressed, kbtrans need
2131 * to set LED. In this case, there is no ioctl from upper module.
2132 * There is no requirement to send response to somebody.
2133 *
2134 * In first case, kbtrans will send response to upper module; and in the
2135 * second, we don't need to send response. So conskbd_streams_setled()
2136 * has no return value.
2137 */
2138 static void
conskbd_streams_setled(struct kbtrans_hardware * hw,int led_state)2139 conskbd_streams_setled(struct kbtrans_hardware *hw, int led_state)
2140 {
2141 conskbd_state_t *conskbdp = (conskbd_state_t *)hw;
2142 conskbd_lower_queue_t *lqs;
2143 mblk_t *req;
2144
2145 ASSERT(&conskbd == conskbdp);
2146
2147 if (led_state == -1)
2148 return;
2149
2150 conskbdp->conskbd_led_state = led_state;
2151
2152 /*
2153 * Basically, failing to set LED is not a fatal error, we just skip
2154 * it if this happens.
2155 */
2156 for (lqs = conskbdp->conskbd_lqueue_list; lqs; lqs = lqs->lqs_next) {
2157 req = mkiocb(KIOCSLED);
2158
2159 if (!req) {
2160 continue;
2161 }
2162
2163 req->b_cont = allocb(sizeof (uchar_t), BPRI_MED);
2164 if (!req->b_cont) {
2165 freemsg(req);
2166 continue;
2167 }
2168 *(uchar_t *)req->b_cont->b_wptr = led_state;
2169 req->b_cont->b_wptr += sizeof (uchar_t);
2170 if (putq(lqs->lqs_queue, req) != 1)
2171 freemsg(req);
2172 }
2173
2174 } /* conskbd_streams_setled() */
2175
2176 static void
conskbd_polledio_setled(struct kbtrans_hardware * hw,int led_state)2177 conskbd_polledio_setled(struct kbtrans_hardware *hw, int led_state)
2178 {
2179 conskbd_state_t *conskbdp = (conskbd_state_t *)hw;
2180 struct cons_polledio *cb;
2181 conskbd_lower_queue_t *lqs;
2182
2183 for (lqs = conskbdp->conskbd_lqueue_list; lqs; lqs = lqs->lqs_next) {
2184 cb = lqs->lqs_polledio;
2185 if ((cb != NULL) && (cb->cons_polledio_setled != NULL)) {
2186 cb->cons_polledio_setled(cb->cons_polledio_argument,
2187 led_state);
2188 }
2189 }
2190
2191 } /* conskbd_polledio_setled() */
2192
2193 static boolean_t
conskbd_polled_keycheck(struct kbtrans_hardware * hw,kbtrans_key_t * keycode,enum keystate * state)2194 conskbd_polled_keycheck(struct kbtrans_hardware *hw,
2195 kbtrans_key_t *keycode, enum keystate *state)
2196 {
2197 conskbd_state_t *conskbdp = (conskbd_state_t *)hw;
2198 struct cons_polledio *cb;
2199 conskbd_lower_queue_t *lqs;
2200 boolean_t ret = B_FALSE;
2201
2202 for (ret = B_FALSE, lqs = conskbdp->conskbd_lqueue_list; lqs != NULL;
2203 lqs = lqs->lqs_next) {
2204 cb = lqs->lqs_polledio;
2205 if ((cb != NULL) &&
2206 (cb->cons_polledio_keycheck != NULL)) {
2207 ret = cb->cons_polledio_keycheck(
2208 cb->cons_polledio_argument, keycode, state);
2209 }
2210
2211 /* Get a char from lower queue(hardware) ? */
2212 if (ret == B_TRUE) {
2213
2214 /* A legacy keyboard ? */
2215 if (conskbd.conskbd_bypassed == B_TRUE)
2216 break;
2217
2218 /*
2219 * This is the PS2 scancode 0x2B -> USB(49) /
2220 * USB(50) keycode mapping workaround, for
2221 * polled mode.
2222 *
2223 * There are two possible USB keycode mappings
2224 * for PS2 scancode 0x2B and this workaround
2225 * makes sure that we use the USB keycode that
2226 * does not end up being mapped to a HOLE key
2227 * using the current keyboard translation
2228 * tables.
2229 *
2230 * See conskbdlrput() for a detailed
2231 * explanation of the problem.
2232 */
2233 if (*keycode == 49 || *keycode == 50) {
2234 if (conskbd_keyindex->k_normal[50] == HOLE)
2235 *keycode = 49;
2236 else
2237 *keycode = 50;
2238 }
2239
2240 break;
2241 }
2242 }
2243
2244 return (ret);
2245
2246 } /* conskbd_polled_keycheck() */
2247
2248 static boolean_t
conskbd_override_kbtrans(queue_t * q,mblk_t * mp)2249 conskbd_override_kbtrans(queue_t *q, mblk_t *mp)
2250 {
2251 struct iocblk *iocp;
2252 int directio;
2253 int error;
2254
2255 if (mp->b_datap->db_type != M_IOCTL)
2256 return (B_FALSE);
2257
2258 iocp = (struct iocblk *)mp->b_rptr;
2259
2260 switch (iocp->ioc_cmd) {
2261 case KIOCGDIRECT: {
2262 /*
2263 * Don't let the kbtrans-based code see this; it will
2264 * respond incorrectly.
2265 */
2266 register mblk_t *datap;
2267
2268 if ((datap = allocb((int)sizeof (int), BPRI_MED)) == NULL) {
2269 miocnak(q, mp, 0, ENOMEM);
2270 return (B_TRUE);
2271 }
2272
2273 *(int *)datap->b_wptr = conskbd.conskbd_directio;
2274 datap->b_wptr += sizeof (int);
2275 if (mp->b_cont) {
2276 freemsg(mp->b_cont);
2277 mp->b_cont = NULL;
2278 }
2279 mp->b_cont = datap;
2280 miocack(q, mp, sizeof (int), 0);
2281 return (B_TRUE);
2282 }
2283
2284 case KIOCSDIRECT:
2285 /*
2286 * Peek at this, set our variables, and then let the kbtrans
2287 * based code see it and respond to it.
2288 */
2289 error = miocpullup(mp, sizeof (int));
2290 if (error != 0) {
2291 return (B_FALSE);
2292 }
2293
2294 directio = *(int *)mp->b_cont->b_rptr;
2295 if (directio != 0 && directio != 1) {
2296 miocnak(q, mp, 0, EINVAL);
2297 return (B_TRUE);
2298 }
2299 conskbd.conskbd_directio = directio;
2300
2301 if (conskbd.conskbd_directio) {
2302 kbtrans_streams_set_queue(
2303 conskbd.conskbd_kbtrans, conskbd_regqueue);
2304 } else {
2305 kbtrans_streams_set_queue(
2306 conskbd.conskbd_kbtrans, conskbd_consqueue);
2307 }
2308
2309 /*
2310 * Let the kbtrans-based code see this and respond to it.
2311 */
2312 return (B_FALSE);
2313
2314 default:
2315 return (B_FALSE);
2316 }
2317
2318 } /* conskbd_override_kbtrans() */
2319
2320
2321 static void
conskbd_polledio_enter(cons_polledio_arg_t arg)2322 conskbd_polledio_enter(cons_polledio_arg_t arg)
2323 {
2324 conskbd_state_t *conskbdp;
2325 struct cons_polledio *cb;
2326 conskbd_lower_queue_t *lqs;
2327
2328 conskbdp = (conskbd_state_t *)arg;
2329 for (lqs = conskbdp->conskbd_lqueue_list; lqs; lqs = lqs->lqs_next) {
2330 cb = lqs->lqs_polledio;
2331 if ((cb != NULL) && (cb->cons_polledio_enter != NULL)) {
2332 cb->cons_polledio_enter(cb->cons_polledio_argument);
2333 }
2334 }
2335
2336 } /* conskbd_polledio_enter() */
2337
2338 static void
conskbd_polledio_exit(cons_polledio_arg_t arg)2339 conskbd_polledio_exit(cons_polledio_arg_t arg)
2340 {
2341 conskbd_state_t *conskbdp;
2342 struct cons_polledio *cb;
2343 conskbd_lower_queue_t *lqs;
2344
2345 conskbdp = (conskbd_state_t *)arg;
2346 for (lqs = conskbdp->conskbd_lqueue_list; lqs; lqs = lqs->lqs_next) {
2347 cb = lqs->lqs_polledio;
2348 if ((cb != NULL) && (cb->cons_polledio_exit != NULL)) {
2349 cb->cons_polledio_exit(cb->cons_polledio_argument);
2350 }
2351 }
2352
2353 } /* conskbd_polledio_exit() */
2354
2355 static int
conskbd_polledio_getchar(cons_polledio_arg_t arg)2356 conskbd_polledio_getchar(cons_polledio_arg_t arg)
2357 {
2358 conskbd_state_t *conskbdp;
2359
2360 conskbdp = (conskbd_state_t *)arg;
2361
2362 return (kbtrans_getchar(conskbdp->conskbd_kbtrans));
2363
2364 } /* conskbd_polledio_getchar() */
2365
2366 static int
conskbd_polledio_ischar(cons_polledio_arg_t arg)2367 conskbd_polledio_ischar(cons_polledio_arg_t arg)
2368 {
2369 conskbd_state_t *conskbdp;
2370
2371 conskbdp = (conskbd_state_t *)arg;
2372
2373 return (kbtrans_ischar(conskbdp->conskbd_kbtrans));
2374
2375 } /* conskbd_polledio_ischar() */
2376
2377
2378 static void
conskbd_mux_enqueue_msg(conskbd_pending_msg_t * msg)2379 conskbd_mux_enqueue_msg(conskbd_pending_msg_t *msg)
2380 {
2381 mutex_enter(&conskbd_msgq_lock);
2382 msg->kpm_next = conskbd_msg_queue;
2383 conskbd_msg_queue = msg;
2384 mutex_exit(&conskbd_msgq_lock);
2385
2386 } /* conskbd_mux_enqueue_msg() */
2387
2388 /*
2389 * the messages in conskbd_msg_queue we just enqueue
2390 */
2391 static conskbd_pending_msg_t *
conskbd_mux_find_msg(mblk_t * mp)2392 conskbd_mux_find_msg(mblk_t *mp)
2393 {
2394 conskbd_pending_msg_t *msg;
2395 struct iocblk *iocp;
2396 uint_t id;
2397
2398 mutex_enter(&conskbd_msgq_lock);
2399 msg = conskbd_msg_queue;
2400
2401 iocp = (struct iocblk *)mp->b_rptr;
2402 ASSERT(iocp);
2403 id = iocp->ioc_id;
2404 while (msg && msg->kpm_req_id != id) {
2405 msg = msg->kpm_next;
2406 }
2407 mutex_exit(&conskbd_msgq_lock);
2408
2409 return (msg);
2410
2411 } /* conskbd_mux_find_msg() */
2412
2413
2414 static void
conskbd_mux_dequeue_msg(conskbd_pending_msg_t * msg)2415 conskbd_mux_dequeue_msg(conskbd_pending_msg_t *msg)
2416 {
2417 conskbd_pending_msg_t *prev;
2418 conskbd_pending_msg_t *p;
2419
2420 mutex_enter(&conskbd_msgq_lock);
2421 prev = conskbd_msg_queue;
2422
2423 for (p = prev; p && p != msg; p = p->kpm_next)
2424 prev = p;
2425
2426 ASSERT(p && p == msg);
2427
2428 if (prev == p) {
2429 conskbd_msg_queue = msg->kpm_next;
2430 } else {
2431 prev->kpm_next = p->kpm_next;
2432 }
2433 p->kpm_next = NULL;
2434 mutex_exit(&conskbd_msgq_lock);
2435
2436 } /* conskbd_mux_dequeue_msg() */
2437
2438 #ifdef DEBUG
2439 /*ARGSUSED*/
2440 void
conskbd_dprintf(const char * fmt,...)2441 conskbd_dprintf(const char *fmt, ...)
2442 {
2443 char buf[256];
2444 va_list ap;
2445
2446 va_start(ap, fmt);
2447 (void) vsprintf(buf, fmt, ap);
2448 va_end(ap);
2449
2450 cmn_err(CE_CONT, "conskbd: %s", buf);
2451
2452 } /* conskbd_dprintf() */
2453 #endif
2454