1 /*
2 * kbdmux.c
3 */
4
5 /*-
6 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
7 *
8 * Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: kbdmux.c,v 1.4 2005/07/14 17:38:35 max Exp $
33 * $FreeBSD$
34 */
35
36 #include "opt_evdev.h"
37 #include "opt_kbd.h"
38 #include "opt_kbdmux.h"
39
40 #include <sys/param.h>
41 #include <sys/bus.h>
42 #include <sys/conf.h>
43 #include <sys/consio.h>
44 #include <sys/fcntl.h>
45 #include <sys/kbio.h>
46 #include <sys/kernel.h>
47 #include <sys/limits.h>
48 #include <sys/lock.h>
49 #include <sys/malloc.h>
50 #include <sys/module.h>
51 #include <sys/mutex.h>
52 #include <sys/poll.h>
53 #include <sys/proc.h>
54 #include <sys/queue.h>
55 #include <sys/selinfo.h>
56 #include <sys/systm.h>
57 #include <sys/taskqueue.h>
58 #include <sys/uio.h>
59 #include <dev/kbd/kbdreg.h>
60
61 /* the initial key map, accent map and fkey strings */
62 #ifdef KBDMUX_DFLT_KEYMAP
63 #define KBD_DFLT_KEYMAP
64 #include "kbdmuxmap.h"
65 #endif
66
67 #include <dev/kbd/kbdtables.h>
68
69 #ifdef EVDEV_SUPPORT
70 #include <dev/evdev/evdev.h>
71 #include <dev/evdev/input.h>
72 #endif
73
74 #define KEYBOARD_NAME "kbdmux"
75
76 MALLOC_DECLARE(M_KBDMUX);
77 MALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor");
78
79 /*****************************************************************************
80 *****************************************************************************
81 ** Keyboard state
82 *****************************************************************************
83 *****************************************************************************/
84
85 #define KBDMUX_Q_SIZE 512 /* input queue size */
86
87 /*
88 * XXX
89 * For now rely on Giant mutex to protect our data structures.
90 * Just like the rest of keyboard drivers and syscons(4) do.
91 * Note that callout is initialized as not MP-safe to make sure
92 * Giant is held.
93 */
94
95 #if 0 /* not yet */
96 #define KBDMUX_LOCK_DECL_GLOBAL \
97 struct mtx ks_lock
98 #define KBDMUX_LOCK_INIT(s) \
99 mtx_init(&(s)->ks_lock, "kbdmux", NULL, MTX_DEF|MTX_RECURSE)
100 #define KBDMUX_LOCK_DESTROY(s) \
101 mtx_destroy(&(s)->ks_lock)
102 #define KBDMUX_LOCK(s) \
103 mtx_lock(&(s)->ks_lock)
104 #define KBDMUX_UNLOCK(s) \
105 mtx_unlock(&(s)->ks_lock)
106 #define KBDMUX_LOCK_ASSERT(s, w) \
107 mtx_assert(&(s)->ks_lock, (w))
108 #else
109 #define KBDMUX_LOCK_DECL_GLOBAL
110
111 #define KBDMUX_LOCK_INIT(s)
112
113 #define KBDMUX_LOCK_DESTROY(s)
114
115 #define KBDMUX_LOCK(s)
116
117 #define KBDMUX_UNLOCK(s)
118
119 #define KBDMUX_LOCK_ASSERT(s, w)
120
121 #endif /* not yet */
122
123 /*
124 * kbdmux keyboard
125 */
126 struct kbdmux_kbd
127 {
128 keyboard_t *kbd; /* keyboard */
129 SLIST_ENTRY(kbdmux_kbd) next; /* link to next */
130 };
131
132 typedef struct kbdmux_kbd kbdmux_kbd_t;
133
134 /*
135 * kbdmux state
136 */
137 struct kbdmux_state
138 {
139 char ks_inq[KBDMUX_Q_SIZE]; /* input chars queue */
140 unsigned int ks_inq_start;
141 unsigned int ks_inq_length;
142 struct task ks_task; /* interrupt task */
143 struct callout ks_timo; /* timeout handler */
144 #define TICKS (hz) /* rate */
145
146 int ks_flags; /* flags */
147 #define COMPOSE (1 << 0) /* compose char flag */
148
149 int ks_polling; /* poll nesting count */
150 int ks_mode; /* K_XLATE, K_RAW, K_CODE */
151 int ks_state; /* state */
152 int ks_accents; /* accent key index (> 0) */
153 u_int ks_composed_char; /* composed char code */
154 u_char ks_prefix; /* AT scan code prefix */
155
156 #ifdef EVDEV_SUPPORT
157 struct evdev_dev * ks_evdev;
158 int ks_evdev_state;
159 #endif
160
161 SLIST_HEAD(, kbdmux_kbd) ks_kbds; /* keyboards */
162
163 KBDMUX_LOCK_DECL_GLOBAL;
164 };
165
166 typedef struct kbdmux_state kbdmux_state_t;
167
168 /*****************************************************************************
169 *****************************************************************************
170 ** Helper functions
171 *****************************************************************************
172 *****************************************************************************/
173
174 static task_fn_t kbdmux_kbd_intr;
175 static callout_func_t kbdmux_kbd_intr_timo;
176 static kbd_callback_func_t kbdmux_kbd_event;
177
178 static void
179 kbdmux_kbd_putc(kbdmux_state_t *state, char c)
180 {
181 unsigned int p;
182
183 if (state->ks_inq_length == KBDMUX_Q_SIZE)
184 return;
185
186 p = (state->ks_inq_start + state->ks_inq_length) % KBDMUX_Q_SIZE;
187 state->ks_inq[p] = c;
188 state->ks_inq_length++;
189 }
190
191 static int
192 kbdmux_kbd_getc(kbdmux_state_t *state)
193 {
194 unsigned char c;
195
196 if (state->ks_inq_length == 0)
197 return (-1);
198
199 c = state->ks_inq[state->ks_inq_start];
200 state->ks_inq_start = (state->ks_inq_start + 1) % KBDMUX_Q_SIZE;
201 state->ks_inq_length--;
202
203 return (c);
204 }
205
206 /*
207 * Interrupt handler task
208 */
209 void
210 kbdmux_kbd_intr(void *xkbd, int pending)
211 {
212 keyboard_t *kbd = (keyboard_t *) xkbd;
213
214 kbdd_intr(kbd, NULL);
215 }
216
217 /*
218 * Schedule interrupt handler on timeout. Called with locked state.
219 */
220 void
221 kbdmux_kbd_intr_timo(void *xstate)
222 {
223 kbdmux_state_t *state = (kbdmux_state_t *) xstate;
224
225 /* queue interrupt task if needed */
226 if (state->ks_inq_length > 0)
227 taskqueue_enqueue(taskqueue_swi_giant, &state->ks_task);
228
229 /* re-schedule timeout */
230 callout_schedule(&state->ks_timo, TICKS);
231 }
232
233 /*
234 * Process event from one of our keyboards
235 */
236 static int
237 kbdmux_kbd_event(keyboard_t *kbd, int event, void *arg)
238 {
239 kbdmux_state_t *state = (kbdmux_state_t *) arg;
240
241 switch (event) {
242 case KBDIO_KEYINPUT: {
243 int c;
244
245 KBDMUX_LOCK(state);
246
247 /*
248 * Read all chars from the keyboard
249 *
250 * Turns out that atkbd(4) check_char() method may return
251 * "true" while read_char() method returns NOKEY. If this
252 * happens we could stuck in the loop below. Avoid this
253 * by breaking out of the loop if read_char() method returns
254 * NOKEY.
255 */
256
257 while (kbdd_check_char(kbd)) {
258 c = kbdd_read_char(kbd, 0);
259 if (c == NOKEY)
260 break;
261 if (c == ERRKEY)
262 continue; /* XXX ring bell */
263 if (!KBD_IS_BUSY(kbd))
264 continue; /* not open - discard the input */
265
266 kbdmux_kbd_putc(state, c);
267 }
268
269 /* queue interrupt task if needed */
270 if (state->ks_inq_length > 0)
271 taskqueue_enqueue(taskqueue_swi_giant, &state->ks_task);
272
273 KBDMUX_UNLOCK(state);
274 } break;
275
276 case KBDIO_UNLOADING: {
277 kbdmux_kbd_t *k;
278
279 KBDMUX_LOCK(state);
280
281 SLIST_FOREACH(k, &state->ks_kbds, next)
282 if (k->kbd == kbd)
283 break;
284
285 if (k != NULL) {
286 kbd_release(k->kbd, &k->kbd);
287 SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
288
289 k->kbd = NULL;
290
291 free(k, M_KBDMUX);
292 }
293
294 KBDMUX_UNLOCK(state);
295 } break;
296
297 default:
298 return (EINVAL);
299 /* NOT REACHED */
300 }
301
302 return (0);
303 }
304
305 /****************************************************************************
306 ****************************************************************************
307 ** Keyboard driver
308 ****************************************************************************
309 ****************************************************************************/
310
311 static int kbdmux_configure(int flags);
312 static kbd_probe_t kbdmux_probe;
313 static kbd_init_t kbdmux_init;
314 static kbd_term_t kbdmux_term;
315 static kbd_intr_t kbdmux_intr;
316 static kbd_test_if_t kbdmux_test_if;
317 static kbd_enable_t kbdmux_enable;
318 static kbd_disable_t kbdmux_disable;
319 static kbd_read_t kbdmux_read;
320 static kbd_check_t kbdmux_check;
321 static kbd_read_char_t kbdmux_read_char;
322 static kbd_check_char_t kbdmux_check_char;
323 static kbd_ioctl_t kbdmux_ioctl;
324 static kbd_lock_t kbdmux_lock;
325 static void kbdmux_clear_state_locked(kbdmux_state_t *state);
326 static kbd_clear_state_t kbdmux_clear_state;
327 static kbd_get_state_t kbdmux_get_state;
328 static kbd_set_state_t kbdmux_set_state;
329 static kbd_poll_mode_t kbdmux_poll;
330
331 static keyboard_switch_t kbdmuxsw = {
332 .probe = kbdmux_probe,
333 .init = kbdmux_init,
334 .term = kbdmux_term,
335 .intr = kbdmux_intr,
336 .test_if = kbdmux_test_if,
337 .enable = kbdmux_enable,
338 .disable = kbdmux_disable,
339 .read = kbdmux_read,
340 .check = kbdmux_check,
341 .read_char = kbdmux_read_char,
342 .check_char = kbdmux_check_char,
343 .ioctl = kbdmux_ioctl,
344 .lock = kbdmux_lock,
345 .clear_state = kbdmux_clear_state,
346 .get_state = kbdmux_get_state,
347 .set_state = kbdmux_set_state,
348 .poll = kbdmux_poll,
349 };
350
351 #ifdef EVDEV_SUPPORT
352 static evdev_event_t kbdmux_ev_event;
353
354 static const struct evdev_methods kbdmux_evdev_methods = {
355 .ev_event = kbdmux_ev_event,
356 };
357 #endif
358
359 /*
360 * Return the number of found keyboards
361 */
362 static int
363 kbdmux_configure(int flags)
364 {
365 return (1);
366 }
367
368 /*
369 * Detect a keyboard
370 */
371 static int
372 kbdmux_probe(int unit, void *arg, int flags)
373 {
374 if (resource_disabled(KEYBOARD_NAME, unit))
375 return (ENXIO);
376
377 return (0);
378 }
379
380 /*
381 * Reset and initialize the keyboard (stolen from atkbd.c)
382 */
383 static int
384 kbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags)
385 {
386 keyboard_t *kbd = NULL;
387 kbdmux_state_t *state = NULL;
388 keymap_t *keymap = NULL;
389 accentmap_t *accmap = NULL;
390 fkeytab_t *fkeymap = NULL;
391 int error, needfree, fkeymap_size, delay[2];
392 #ifdef EVDEV_SUPPORT
393 struct evdev_dev *evdev;
394 char phys_loc[NAMELEN];
395 #endif
396
397 if (*kbdp == NULL) {
398 *kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO);
399 state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO);
400 keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT);
401 accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT);
402 fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT);
403 fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);
404 needfree = 1;
405
406 if ((kbd == NULL) || (state == NULL) || (keymap == NULL) ||
407 (accmap == NULL) || (fkeymap == NULL)) {
408 error = ENOMEM;
409 goto bad;
410 }
411
412 KBDMUX_LOCK_INIT(state);
413 TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd);
414 callout_init(&state->ks_timo, 1);
415 SLIST_INIT(&state->ks_kbds);
416 } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) {
417 return (0);
418 } else {
419 kbd = *kbdp;
420 state = (kbdmux_state_t *) kbd->kb_data;
421 keymap = kbd->kb_keymap;
422 accmap = kbd->kb_accentmap;
423 fkeymap = kbd->kb_fkeytab;
424 fkeymap_size = kbd->kb_fkeytab_size;
425 needfree = 0;
426 }
427
428 if (!KBD_IS_PROBED(kbd)) {
429 /* XXX assume 101/102 keys keyboard */
430 kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags, 0, 0);
431 bcopy(&key_map, keymap, sizeof(key_map));
432 bcopy(&accent_map, accmap, sizeof(accent_map));
433 bcopy(fkey_tab, fkeymap,
434 imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab)));
435 kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size);
436 kbd->kb_data = (void *)state;
437
438 KBD_FOUND_DEVICE(kbd);
439 KBD_PROBE_DONE(kbd);
440
441 KBDMUX_LOCK(state);
442 kbdmux_clear_state_locked(state);
443 state->ks_mode = K_XLATE;
444 KBDMUX_UNLOCK(state);
445 }
446
447 if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) {
448 kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY;
449
450 kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state);
451
452 delay[0] = kbd->kb_delay1;
453 delay[1] = kbd->kb_delay2;
454 kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
455
456 #ifdef EVDEV_SUPPORT
457 /* register as evdev provider */
458 evdev = evdev_alloc();
459 evdev_set_name(evdev, "System keyboard multiplexer");
460 snprintf(phys_loc, NAMELEN, KEYBOARD_NAME"%d", unit);
461 evdev_set_phys(evdev, phys_loc);
462 evdev_set_id(evdev, BUS_VIRTUAL, 0, 0, 0);
463 evdev_set_methods(evdev, kbd, &kbdmux_evdev_methods);
464 evdev_support_event(evdev, EV_SYN);
465 evdev_support_event(evdev, EV_KEY);
466 evdev_support_event(evdev, EV_LED);
467 evdev_support_event(evdev, EV_REP);
468 evdev_support_all_known_keys(evdev);
469 evdev_support_led(evdev, LED_NUML);
470 evdev_support_led(evdev, LED_CAPSL);
471 evdev_support_led(evdev, LED_SCROLLL);
472
473 if (evdev_register_mtx(evdev, &Giant))
474 evdev_free(evdev);
475 else
476 state->ks_evdev = evdev;
477 state->ks_evdev_state = 0;
478 #endif
479
480 KBD_INIT_DONE(kbd);
481 }
482
483 if (!KBD_IS_CONFIGURED(kbd)) {
484 if (kbd_register(kbd) < 0) {
485 error = ENXIO;
486 goto bad;
487 }
488
489 KBD_CONFIG_DONE(kbd);
490
491 callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state);
492 }
493
494 return (0);
495 bad:
496 if (needfree) {
497 if (state != NULL)
498 free(state, M_KBDMUX);
499 if (keymap != NULL)
500 free(keymap, M_KBDMUX);
501 if (accmap != NULL)
502 free(accmap, M_KBDMUX);
503 if (fkeymap != NULL)
504 free(fkeymap, M_KBDMUX);
505 if (kbd != NULL) {
506 free(kbd, M_KBDMUX);
507 *kbdp = NULL; /* insure ref doesn't leak to caller */
508 }
509 }
510
511 return (error);
512 }
513
514 /*
515 * Finish using this keyboard
516 */
517 static int
518 kbdmux_term(keyboard_t *kbd)
519 {
520 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
521 kbdmux_kbd_t *k;
522
523 /* release all keyboards from the mux */
524 KBDMUX_LOCK(state);
525 while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) {
526 kbd_release(k->kbd, &k->kbd);
527 SLIST_REMOVE_HEAD(&state->ks_kbds, next);
528
529 k->kbd = NULL;
530
531 free(k, M_KBDMUX);
532 }
533 KBDMUX_UNLOCK(state);
534
535 callout_drain(&state->ks_timo);
536 taskqueue_drain(taskqueue_swi_giant, &state->ks_task);
537
538 kbd_unregister(kbd);
539
540 #ifdef EVDEV_SUPPORT
541 evdev_free(state->ks_evdev);
542 #endif
543
544 KBDMUX_LOCK_DESTROY(state);
545 bzero(state, sizeof(*state));
546 free(state, M_KBDMUX);
547
548 free(kbd->kb_keymap, M_KBDMUX);
549 free(kbd->kb_accentmap, M_KBDMUX);
550 free(kbd->kb_fkeytab, M_KBDMUX);
551 free(kbd, M_KBDMUX);
552
553 return (0);
554 }
555
556 /*
557 * Keyboard interrupt routine
558 */
559 static int
560 kbdmux_intr(keyboard_t *kbd, void *arg)
561 {
562 int c;
563
564 if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) {
565 /* let the callback function to process the input */
566 (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT,
567 kbd->kb_callback.kc_arg);
568 } else {
569 /* read and discard the input; no one is waiting for input */
570 do {
571 c = kbdmux_read_char(kbd, FALSE);
572 } while (c != NOKEY);
573 }
574
575 return (0);
576 }
577
578 /*
579 * Test the interface to the device
580 */
581 static int
582 kbdmux_test_if(keyboard_t *kbd)
583 {
584 return (0);
585 }
586
587 /*
588 * Enable the access to the device; until this function is called,
589 * the client cannot read from the keyboard.
590 */
591 static int
592 kbdmux_enable(keyboard_t *kbd)
593 {
594 KBD_ACTIVATE(kbd);
595 return (0);
596 }
597
598 /*
599 * Disallow the access to the device
600 */
601 static int
602 kbdmux_disable(keyboard_t *kbd)
603 {
604 KBD_DEACTIVATE(kbd);
605 return (0);
606 }
607
608 /*
609 * Read one byte from the keyboard if it's allowed
610 */
611 static int
612 kbdmux_read(keyboard_t *kbd, int wait)
613 {
614 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
615 int c;
616
617 KBDMUX_LOCK(state);
618 c = kbdmux_kbd_getc(state);
619 KBDMUX_UNLOCK(state);
620
621 if (c != -1)
622 kbd->kb_count ++;
623
624 return (KBD_IS_ACTIVE(kbd)? c : -1);
625 }
626
627 /*
628 * Check if data is waiting
629 */
630 static int
631 kbdmux_check(keyboard_t *kbd)
632 {
633 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
634 int ready;
635
636 if (!KBD_IS_ACTIVE(kbd))
637 return (FALSE);
638
639 KBDMUX_LOCK(state);
640 ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
641 KBDMUX_UNLOCK(state);
642
643 return (ready);
644 }
645
646 /*
647 * Read char from the keyboard (stolen from atkbd.c)
648 */
649 static u_int
650 kbdmux_read_char(keyboard_t *kbd, int wait)
651 {
652 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
653 u_int action;
654 int scancode, keycode;
655
656 KBDMUX_LOCK(state);
657
658 next_code:
659
660 /* do we have a composed char to return? */
661 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) {
662 action = state->ks_composed_char;
663 state->ks_composed_char = 0;
664 if (action > UCHAR_MAX) {
665 KBDMUX_UNLOCK(state);
666
667 return (ERRKEY);
668 }
669
670 KBDMUX_UNLOCK(state);
671
672 return (action);
673 }
674
675 /* see if there is something in the keyboard queue */
676 scancode = kbdmux_kbd_getc(state);
677 if (scancode == -1) {
678 if (state->ks_polling != 0) {
679 kbdmux_kbd_t *k;
680
681 SLIST_FOREACH(k, &state->ks_kbds, next) {
682 while (kbdd_check_char(k->kbd)) {
683 scancode = kbdd_read_char(k->kbd, 0);
684 if (scancode == NOKEY)
685 break;
686 if (scancode == ERRKEY)
687 continue;
688 if (!KBD_IS_BUSY(k->kbd))
689 continue;
690
691 kbdmux_kbd_putc(state, scancode);
692 }
693 }
694
695 if (state->ks_inq_length > 0)
696 goto next_code;
697 }
698
699 KBDMUX_UNLOCK(state);
700 return (NOKEY);
701 }
702 /* XXX FIXME: check for -1 if wait == 1! */
703
704 kbd->kb_count ++;
705
706 #ifdef EVDEV_SUPPORT
707 /* push evdev event */
708 if (evdev_rcpt_mask & EVDEV_RCPT_KBDMUX && state->ks_evdev != NULL) {
709 uint16_t key = evdev_scancode2key(&state->ks_evdev_state,
710 scancode);
711
712 if (key != KEY_RESERVED) {
713 evdev_push_event(state->ks_evdev, EV_KEY,
714 key, scancode & 0x80 ? 0 : 1);
715 evdev_sync(state->ks_evdev);
716 }
717 }
718 #endif
719
720 /* return the byte as is for the K_RAW mode */
721 if (state->ks_mode == K_RAW) {
722 KBDMUX_UNLOCK(state);
723 return (scancode);
724 }
725
726 /* translate the scan code into a keycode */
727 keycode = scancode & 0x7F;
728 switch (state->ks_prefix) {
729 case 0x00: /* normal scancode */
730 switch(scancode) {
731 case 0xB8: /* left alt (compose key) released */
732 if (state->ks_flags & COMPOSE) {
733 state->ks_flags &= ~COMPOSE;
734 if (state->ks_composed_char > UCHAR_MAX)
735 state->ks_composed_char = 0;
736 }
737 break;
738 case 0x38: /* left alt (compose key) pressed */
739 if (!(state->ks_flags & COMPOSE)) {
740 state->ks_flags |= COMPOSE;
741 state->ks_composed_char = 0;
742 }
743 break;
744 case 0xE0:
745 case 0xE1:
746 state->ks_prefix = scancode;
747 goto next_code;
748 }
749 break;
750 case 0xE0: /* 0xE0 prefix */
751 state->ks_prefix = 0;
752 switch (keycode) {
753 case 0x1C: /* right enter key */
754 keycode = 0x59;
755 break;
756 case 0x1D: /* right ctrl key */
757 keycode = 0x5A;
758 break;
759 case 0x35: /* keypad divide key */
760 keycode = 0x5B;
761 break;
762 case 0x37: /* print scrn key */
763 keycode = 0x5C;
764 break;
765 case 0x38: /* right alt key (alt gr) */
766 keycode = 0x5D;
767 break;
768 case 0x46: /* ctrl-pause/break on AT 101 (see below) */
769 keycode = 0x68;
770 break;
771 case 0x47: /* grey home key */
772 keycode = 0x5E;
773 break;
774 case 0x48: /* grey up arrow key */
775 keycode = 0x5F;
776 break;
777 case 0x49: /* grey page up key */
778 keycode = 0x60;
779 break;
780 case 0x4B: /* grey left arrow key */
781 keycode = 0x61;
782 break;
783 case 0x4D: /* grey right arrow key */
784 keycode = 0x62;
785 break;
786 case 0x4F: /* grey end key */
787 keycode = 0x63;
788 break;
789 case 0x50: /* grey down arrow key */
790 keycode = 0x64;
791 break;
792 case 0x51: /* grey page down key */
793 keycode = 0x65;
794 break;
795 case 0x52: /* grey insert key */
796 keycode = 0x66;
797 break;
798 case 0x53: /* grey delete key */
799 keycode = 0x67;
800 break;
801 /* the following 3 are only used on the MS "Natural" keyboard */
802 case 0x5b: /* left Window key */
803 keycode = 0x69;
804 break;
805 case 0x5c: /* right Window key */
806 keycode = 0x6a;
807 break;
808 case 0x5d: /* menu key */
809 keycode = 0x6b;
810 break;
811 case 0x5e: /* power key */
812 keycode = 0x6d;
813 break;
814 case 0x5f: /* sleep key */
815 keycode = 0x6e;
816 break;
817 case 0x63: /* wake key */
818 keycode = 0x6f;
819 break;
820 case 0x64: /* [JP106USB] backslash, underscore */
821 keycode = 0x73;
822 break;
823 default: /* ignore everything else */
824 goto next_code;
825 }
826 break;
827 case 0xE1: /* 0xE1 prefix */
828 /*
829 * The pause/break key on the 101 keyboard produces:
830 * E1-1D-45 E1-9D-C5
831 * Ctrl-pause/break produces:
832 * E0-46 E0-C6 (See above.)
833 */
834 state->ks_prefix = 0;
835 if (keycode == 0x1D)
836 state->ks_prefix = 0x1D;
837 goto next_code;
838 /* NOT REACHED */
839 case 0x1D: /* pause / break */
840 state->ks_prefix = 0;
841 if (keycode != 0x45)
842 goto next_code;
843 keycode = 0x68;
844 break;
845 }
846
847 /* XXX assume 101/102 keys AT keyboard */
848 switch (keycode) {
849 case 0x5c: /* print screen */
850 if (state->ks_flags & ALTS)
851 keycode = 0x54; /* sysrq */
852 break;
853 case 0x68: /* pause/break */
854 if (state->ks_flags & CTLS)
855 keycode = 0x6c; /* break */
856 break;
857 }
858
859 /* return the key code in the K_CODE mode */
860 if (state->ks_mode == K_CODE) {
861 KBDMUX_UNLOCK(state);
862 return (keycode | (scancode & 0x80));
863 }
864
865 /* compose a character code */
866 if (state->ks_flags & COMPOSE) {
867 switch (keycode | (scancode & 0x80)) {
868 /* key pressed, process it */
869 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */
870 state->ks_composed_char *= 10;
871 state->ks_composed_char += keycode - 0x40;
872 if (state->ks_composed_char > UCHAR_MAX) {
873 KBDMUX_UNLOCK(state);
874 return (ERRKEY);
875 }
876 goto next_code;
877 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */
878 state->ks_composed_char *= 10;
879 state->ks_composed_char += keycode - 0x47;
880 if (state->ks_composed_char > UCHAR_MAX) {
881 KBDMUX_UNLOCK(state);
882 return (ERRKEY);
883 }
884 goto next_code;
885 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */
886 state->ks_composed_char *= 10;
887 state->ks_composed_char += keycode - 0x4E;
888 if (state->ks_composed_char > UCHAR_MAX) {
889 KBDMUX_UNLOCK(state);
890 return (ERRKEY);
891 }
892 goto next_code;
893 case 0x52: /* keypad 0 */
894 state->ks_composed_char *= 10;
895 if (state->ks_composed_char > UCHAR_MAX) {
896 KBDMUX_UNLOCK(state);
897 return (ERRKEY);
898 }
899 goto next_code;
900
901 /* key released, no interest here */
902 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */
903 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */
904 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */
905 case 0xD2: /* keypad 0 */
906 goto next_code;
907
908 case 0x38: /* left alt key */
909 break;
910
911 default:
912 if (state->ks_composed_char > 0) {
913 state->ks_flags &= ~COMPOSE;
914 state->ks_composed_char = 0;
915 KBDMUX_UNLOCK(state);
916 return (ERRKEY);
917 }
918 break;
919 }
920 }
921
922 /* keycode to key action */
923 action = genkbd_keyaction(kbd, keycode, scancode & 0x80,
924 &state->ks_state, &state->ks_accents);
925 if (action == NOKEY)
926 goto next_code;
927
928 KBDMUX_UNLOCK(state);
929
930 return (action);
931 }
932
933 /*
934 * Check if char is waiting
935 */
936 static int
937 kbdmux_check_char(keyboard_t *kbd)
938 {
939 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
940 int ready;
941
942 if (!KBD_IS_ACTIVE(kbd))
943 return (FALSE);
944
945 KBDMUX_LOCK(state);
946
947 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0))
948 ready = TRUE;
949 else
950 ready = (state->ks_inq_length > 0) ? TRUE : FALSE;
951
952 KBDMUX_UNLOCK(state);
953
954 return (ready);
955 }
956
957 /*
958 * Keyboard ioctl's
959 */
960 static int
961 kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg)
962 {
963 static int delays[] = {
964 250, 500, 750, 1000
965 };
966
967 static int rates[] = {
968 34, 38, 42, 46, 50, 55, 59, 63,
969 68, 76, 84, 92, 100, 110, 118, 126,
970 136, 152, 168, 184, 200, 220, 236, 252,
971 272, 304, 336, 368, 400, 440, 472, 504
972 };
973
974 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
975 kbdmux_kbd_t *k;
976 keyboard_info_t *ki;
977 int error = 0, mode;
978 #ifdef COMPAT_FREEBSD6
979 int ival;
980 #endif
981
982 if (state == NULL)
983 return (ENXIO);
984
985 switch (cmd) {
986 case KBADDKBD: /* add keyboard to the mux */
987 ki = (keyboard_info_t *) arg;
988
989 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
990 strcmp(ki->kb_name, "*") == 0)
991 return (EINVAL); /* bad input */
992
993 KBDMUX_LOCK(state);
994
995 SLIST_FOREACH(k, &state->ks_kbds, next)
996 if (k->kbd->kb_unit == ki->kb_unit &&
997 strcmp(k->kbd->kb_name, ki->kb_name) == 0)
998 break;
999
1000 if (k != NULL) {
1001 KBDMUX_UNLOCK(state);
1002
1003 return (0); /* keyboard already in the mux */
1004 }
1005
1006 k = malloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO);
1007 if (k == NULL) {
1008 KBDMUX_UNLOCK(state);
1009
1010 return (ENOMEM); /* out of memory */
1011 }
1012
1013 k->kbd = kbd_get_keyboard(
1014 kbd_allocate(
1015 ki->kb_name,
1016 ki->kb_unit,
1017 (void *) &k->kbd,
1018 kbdmux_kbd_event, (void *) state));
1019 if (k->kbd == NULL) {
1020 KBDMUX_UNLOCK(state);
1021 free(k, M_KBDMUX);
1022
1023 return (EINVAL); /* bad keyboard */
1024 }
1025
1026 kbdd_enable(k->kbd);
1027 kbdd_clear_state(k->kbd);
1028
1029 /* set K_RAW mode on slave keyboard */
1030 mode = K_RAW;
1031 error = kbdd_ioctl(k->kbd, KDSKBMODE, (caddr_t)&mode);
1032 if (error == 0) {
1033 /* set lock keys state on slave keyboard */
1034 mode = state->ks_state & LOCK_MASK;
1035 error = kbdd_ioctl(k->kbd, KDSKBSTATE, (caddr_t)&mode);
1036 }
1037
1038 if (error != 0) {
1039 KBDMUX_UNLOCK(state);
1040
1041 kbd_release(k->kbd, &k->kbd);
1042 k->kbd = NULL;
1043
1044 free(k, M_KBDMUX);
1045
1046 return (error); /* could not set mode */
1047 }
1048
1049 SLIST_INSERT_HEAD(&state->ks_kbds, k, next);
1050
1051 KBDMUX_UNLOCK(state);
1052 break;
1053
1054 case KBRELKBD: /* release keyboard from the mux */
1055 ki = (keyboard_info_t *) arg;
1056
1057 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' ||
1058 strcmp(ki->kb_name, "*") == 0)
1059 return (EINVAL); /* bad input */
1060
1061 KBDMUX_LOCK(state);
1062
1063 SLIST_FOREACH(k, &state->ks_kbds, next)
1064 if (k->kbd->kb_unit == ki->kb_unit &&
1065 strcmp(k->kbd->kb_name, ki->kb_name) == 0)
1066 break;
1067
1068 if (k != NULL) {
1069 error = kbd_release(k->kbd, &k->kbd);
1070 if (error == 0) {
1071 SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next);
1072
1073 k->kbd = NULL;
1074
1075 free(k, M_KBDMUX);
1076 }
1077 } else
1078 error = ENXIO; /* keyboard is not in the mux */
1079
1080 KBDMUX_UNLOCK(state);
1081 break;
1082
1083 case KDGKBMODE: /* get kyboard mode */
1084 KBDMUX_LOCK(state);
1085 *(int *)arg = state->ks_mode;
1086 KBDMUX_UNLOCK(state);
1087 break;
1088
1089 #ifdef COMPAT_FREEBSD6
1090 case _IO('K', 7):
1091 ival = IOCPARM_IVAL(arg);
1092 arg = (caddr_t)&ival;
1093 /* FALLTHROUGH */
1094 #endif
1095 case KDSKBMODE: /* set keyboard mode */
1096 KBDMUX_LOCK(state);
1097
1098 switch (*(int *)arg) {
1099 case K_XLATE:
1100 if (state->ks_mode != K_XLATE) {
1101 /* make lock key state and LED state match */
1102 state->ks_state &= ~LOCK_MASK;
1103 state->ks_state |= KBD_LED_VAL(kbd);
1104 }
1105 /* FALLTHROUGH */
1106
1107 case K_RAW:
1108 case K_CODE:
1109 if (state->ks_mode != *(int *)arg) {
1110 kbdmux_clear_state_locked(state);
1111 state->ks_mode = *(int *)arg;
1112 }
1113 break;
1114
1115 default:
1116 error = EINVAL;
1117 break;
1118 }
1119
1120 KBDMUX_UNLOCK(state);
1121 break;
1122
1123 case KDGETLED: /* get keyboard LED */
1124 KBDMUX_LOCK(state);
1125 *(int *)arg = KBD_LED_VAL(kbd);
1126 KBDMUX_UNLOCK(state);
1127 break;
1128
1129 #ifdef COMPAT_FREEBSD6
1130 case _IO('K', 66):
1131 ival = IOCPARM_IVAL(arg);
1132 arg = (caddr_t)&ival;
1133 /* FALLTHROUGH */
1134 #endif
1135 case KDSETLED: /* set keyboard LED */
1136 KBDMUX_LOCK(state);
1137
1138 /* NOTE: lock key state in ks_state won't be changed */
1139 if (*(int *)arg & ~LOCK_MASK) {
1140 KBDMUX_UNLOCK(state);
1141
1142 return (EINVAL);
1143 }
1144
1145 KBD_LED_VAL(kbd) = *(int *)arg;
1146 #ifdef EVDEV_SUPPORT
1147 if (state->ks_evdev != NULL &&
1148 evdev_rcpt_mask & EVDEV_RCPT_KBDMUX)
1149 evdev_push_leds(state->ks_evdev, *(int *)arg);
1150 #endif
1151 /* KDSETLED on all slave keyboards */
1152 SLIST_FOREACH(k, &state->ks_kbds, next)
1153 (void)kbdd_ioctl(k->kbd, KDSETLED, arg);
1154
1155 KBDMUX_UNLOCK(state);
1156 break;
1157
1158 case KDGKBSTATE: /* get lock key state */
1159 KBDMUX_LOCK(state);
1160 *(int *)arg = state->ks_state & LOCK_MASK;
1161 KBDMUX_UNLOCK(state);
1162 break;
1163
1164 #ifdef COMPAT_FREEBSD6
1165 case _IO('K', 20):
1166 ival = IOCPARM_IVAL(arg);
1167 arg = (caddr_t)&ival;
1168 /* FALLTHROUGH */
1169 #endif
1170 case KDSKBSTATE: /* set lock key state */
1171 KBDMUX_LOCK(state);
1172
1173 if (*(int *)arg & ~LOCK_MASK) {
1174 KBDMUX_UNLOCK(state);
1175
1176 return (EINVAL);
1177 }
1178
1179 state->ks_state &= ~LOCK_MASK;
1180 state->ks_state |= *(int *)arg;
1181
1182 /* KDSKBSTATE on all slave keyboards */
1183 SLIST_FOREACH(k, &state->ks_kbds, next)
1184 (void)kbdd_ioctl(k->kbd, KDSKBSTATE, arg);
1185
1186 KBDMUX_UNLOCK(state);
1187
1188 return (kbdmux_ioctl(kbd, KDSETLED, arg));
1189 /* NOT REACHED */
1190
1191 #ifdef COMPAT_FREEBSD6
1192 case _IO('K', 67):
1193 cmd = KDSETRAD;
1194 ival = IOCPARM_IVAL(arg);
1195 arg = (caddr_t)&ival;
1196 /* FALLTHROUGH */
1197 #endif
1198 case KDSETREPEAT: /* set keyboard repeat rate (new interface) */
1199 case KDSETRAD: /* set keyboard repeat rate (old interface) */
1200 KBDMUX_LOCK(state);
1201
1202 if (cmd == KDSETREPEAT) {
1203 int i;
1204
1205 /* lookup delay */
1206 for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --)
1207 if (((int *)arg)[0] >= delays[i])
1208 break;
1209 mode = i << 5;
1210
1211 /* lookup rate */
1212 for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --)
1213 if (((int *)arg)[1] >= rates[i])
1214 break;
1215 mode |= i;
1216 } else
1217 mode = *(int *)arg;
1218
1219 if (mode & ~0x7f) {
1220 KBDMUX_UNLOCK(state);
1221
1222 return (EINVAL);
1223 }
1224
1225 kbd->kb_delay1 = delays[(mode >> 5) & 3];
1226 kbd->kb_delay2 = rates[mode & 0x1f];
1227 #ifdef EVDEV_SUPPORT
1228 if (state->ks_evdev != NULL &&
1229 evdev_rcpt_mask & EVDEV_RCPT_KBDMUX)
1230 evdev_push_repeats(state->ks_evdev, kbd);
1231 #endif
1232 /* perform command on all slave keyboards */
1233 SLIST_FOREACH(k, &state->ks_kbds, next)
1234 (void)kbdd_ioctl(k->kbd, cmd, arg);
1235
1236 KBDMUX_UNLOCK(state);
1237 break;
1238
1239 case PIO_KEYMAP: /* set keyboard translation table */
1240 case OPIO_KEYMAP: /* set keyboard translation table (compat) */
1241 case PIO_KEYMAPENT: /* set keyboard translation table entry */
1242 case PIO_DEADKEYMAP: /* set accent key translation table */
1243 KBDMUX_LOCK(state);
1244 state->ks_accents = 0;
1245
1246 /* perform command on all slave keyboards */
1247 SLIST_FOREACH(k, &state->ks_kbds, next)
1248 (void)kbdd_ioctl(k->kbd, cmd, arg);
1249
1250 KBDMUX_UNLOCK(state);
1251 /* FALLTHROUGH */
1252
1253 default:
1254 error = genkbd_commonioctl(kbd, cmd, arg);
1255 break;
1256 }
1257
1258 return (error);
1259 }
1260
1261 /*
1262 * Lock the access to the keyboard
1263 */
1264 static int
1265 kbdmux_lock(keyboard_t *kbd, int lock)
1266 {
1267 return (1); /* XXX */
1268 }
1269
1270 /*
1271 * Clear the internal state of the keyboard
1272 */
1273 static void
1274 kbdmux_clear_state_locked(kbdmux_state_t *state)
1275 {
1276 KBDMUX_LOCK_ASSERT(state, MA_OWNED);
1277
1278 state->ks_flags &= ~COMPOSE;
1279 state->ks_polling = 0;
1280 state->ks_state &= LOCK_MASK; /* preserve locking key state */
1281 state->ks_accents = 0;
1282 state->ks_composed_char = 0;
1283 /* state->ks_prefix = 0; XXX */
1284 state->ks_inq_length = 0;
1285 }
1286
1287 static void
1288 kbdmux_clear_state(keyboard_t *kbd)
1289 {
1290 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
1291
1292 KBDMUX_LOCK(state);
1293 kbdmux_clear_state_locked(state);
1294 KBDMUX_UNLOCK(state);
1295 }
1296
1297 /*
1298 * Save the internal state
1299 */
1300 static int
1301 kbdmux_get_state(keyboard_t *kbd, void *buf, size_t len)
1302 {
1303 if (len == 0)
1304 return (sizeof(kbdmux_state_t));
1305 if (len < sizeof(kbdmux_state_t))
1306 return (-1);
1307
1308 bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */
1309
1310 return (0);
1311 }
1312
1313 /*
1314 * Set the internal state
1315 */
1316 static int
1317 kbdmux_set_state(keyboard_t *kbd, void *buf, size_t len)
1318 {
1319 if (len < sizeof(kbdmux_state_t))
1320 return (ENOMEM);
1321
1322 bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */
1323
1324 return (0);
1325 }
1326
1327 /*
1328 * Set polling
1329 */
1330 static int
1331 kbdmux_poll(keyboard_t *kbd, int on)
1332 {
1333 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data;
1334 kbdmux_kbd_t *k;
1335
1336 KBDMUX_LOCK(state);
1337
1338 if (on)
1339 state->ks_polling++;
1340 else
1341 state->ks_polling--;
1342
1343 /* set poll on slave keyboards */
1344 SLIST_FOREACH(k, &state->ks_kbds, next)
1345 kbdd_poll(k->kbd, on);
1346
1347 KBDMUX_UNLOCK(state);
1348
1349 return (0);
1350 }
1351
1352 #ifdef EVDEV_SUPPORT
1353 static void
1354 kbdmux_ev_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
1355 int32_t value)
1356 {
1357 keyboard_t *kbd = evdev_get_softc(evdev);
1358
1359 if (evdev_rcpt_mask & EVDEV_RCPT_KBDMUX &&
1360 (type == EV_LED || type == EV_REP)) {
1361 mtx_lock(&Giant);
1362 kbd_ev_event(kbd, type, code, value);
1363 mtx_unlock(&Giant);
1364 }
1365 }
1366 #endif
1367
1368 /*****************************************************************************
1369 *****************************************************************************
1370 ** Module
1371 *****************************************************************************
1372 *****************************************************************************/
1373
1374 KEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure);
1375
1376 static int
1377 kbdmux_modevent(module_t mod, int type, void *data)
1378 {
1379 keyboard_switch_t *sw;
1380 keyboard_t *kbd;
1381 int error;
1382
1383 switch (type) {
1384 case MOD_LOAD:
1385 if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0)
1386 break;
1387
1388 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
1389 error = ENXIO;
1390 break;
1391 }
1392
1393 kbd = NULL;
1394
1395 if ((error = (*sw->probe)(0, NULL, 0)) != 0 ||
1396 (error = (*sw->init)(0, &kbd, NULL, 0)) != 0)
1397 break;
1398
1399 #ifdef KBD_INSTALL_CDEV
1400 if ((error = kbd_attach(kbd)) != 0) {
1401 (*sw->term)(kbd);
1402 break;
1403 }
1404 #endif
1405
1406 if ((error = (*sw->enable)(kbd)) != 0)
1407 break;
1408 break;
1409
1410 case MOD_UNLOAD:
1411 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) {
1412 error = 0;
1413 break;
1414 }
1415
1416 kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0));
1417 if (kbd != NULL) {
1418 (*sw->disable)(kbd);
1419 #ifdef KBD_INSTALL_CDEV
1420 kbd_detach(kbd);
1421 #endif
1422 (*sw->term)(kbd);
1423 }
1424 kbd_delete_driver(&kbdmux_kbd_driver);
1425 error = 0;
1426 break;
1427
1428 default:
1429 error = EOPNOTSUPP;
1430 break;
1431 }
1432
1433 return (error);
1434 }
1435
1436 DEV_MODULE(kbdmux, kbdmux_modevent, NULL);
1437 #ifdef EVDEV_SUPPORT
1438 MODULE_DEPEND(kbdmux, evdev, 1, 1, 1);
1439 #endif
Cache object: 03cb2e71bccd0ae913e86cb10152dcb3
|