adb_kbd.c revision 1.21 1 /* $NetBSD: adb_kbd.c,v 1.21 2012/09/19 04:55:06 macallan Exp $ */
2
3 /*
4 * Copyright (C) 1998 Colin Wood
5 * Copyright (C) 2006, 2007 Michael Lorenz
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Colin Wood.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: adb_kbd.c,v 1.21 2012/09/19 04:55:06 macallan Exp $");
36
37 #include <sys/param.h>
38 #include <sys/device.h>
39 #include <sys/fcntl.h>
40 #include <sys/poll.h>
41 #include <sys/select.h>
42 #include <sys/proc.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/sysctl.h>
46
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wscons/wskbdvar.h>
49 #include <dev/wscons/wsksymdef.h>
50 #include <dev/wscons/wsksymvar.h>
51 #include <dev/wscons/wsmousevar.h>
52
53 #include <dev/sysmon/sysmonvar.h>
54 #include <dev/sysmon/sysmon_taskq.h>
55
56 #include <machine/autoconf.h>
57 #include <machine/keyboard.h>
58 #include <machine/adbsys.h>
59
60 #include <dev/adb/adbvar.h>
61 #include <dev/adb/adb_keymap.h>
62
63 #include "opt_wsdisplay_compat.h"
64 #include "opt_adbkbd.h"
65 #include "adbdebug.h"
66 #include "wsmouse.h"
67
68 struct adbkbd_softc {
69 device_t sc_dev;
70 struct adb_device *sc_adbdev;
71 struct adb_bus_accessops *sc_ops;
72 device_t sc_wskbddev;
73 #if NWSMOUSE > 0
74 device_t sc_wsmousedev;
75 #endif
76 struct sysmon_pswitch sc_sm_pbutton;
77 int sc_leds;
78 int sc_have_led_control;
79 int sc_power_button_delay;
80 int sc_msg_len;
81 int sc_event;
82 int sc_poll;
83 int sc_polled_chars;
84 int sc_trans[3];
85 int sc_capslock;
86 uint32_t sc_timestamp;
87 #ifdef WSDISPLAY_COMPAT_RAWKBD
88 int sc_rawkbd;
89 #endif
90 bool sc_emul_usb;
91
92 uint32_t sc_power;
93 uint8_t sc_buffer[16];
94 uint8_t sc_pollbuf[16];
95 uint8_t sc_us, sc_pe;
96 };
97
98 /*
99 * Function declarations.
100 */
101 static int adbkbd_match(device_t, cfdata_t, void *);
102 static void adbkbd_attach(device_t, device_t, void *);
103
104 static void adbkbd_initleds(struct adbkbd_softc *);
105 static void adbkbd_keys(struct adbkbd_softc *, uint8_t, uint8_t);
106 static inline void adbkbd_key(struct adbkbd_softc *, uint8_t);
107 static int adbkbd_wait(struct adbkbd_softc *, int);
108
109 /* Driver definition. */
110 CFATTACH_DECL_NEW(adbkbd, sizeof(struct adbkbd_softc),
111 adbkbd_match, adbkbd_attach, NULL, NULL);
112
113 extern struct cfdriver adbkbd_cd;
114
115 static int adbkbd_enable(void *, int);
116 static int adbkbd_ioctl(void *, u_long, void *, int, struct lwp *);
117 static void adbkbd_set_leds(void *, int);
118 static void adbkbd_handler(void *, int, uint8_t *);
119 static void adbkbd_powerbutton(void *);
120
121 struct wskbd_accessops adbkbd_accessops = {
122 adbkbd_enable,
123 adbkbd_set_leds,
124 adbkbd_ioctl,
125 };
126
127 static void adbkbd_cngetc(void *, u_int *, int *);
128 static void adbkbd_cnpollc(void *, int);
129
130 struct wskbd_consops adbkbd_consops = {
131 adbkbd_cngetc,
132 adbkbd_cnpollc,
133 };
134
135 struct wskbd_mapdata adbkbd_keymapdata = {
136 akbd_keydesctab,
137 #ifdef AKBD_LAYOUT
138 AKBD_LAYOUT,
139 #else
140 KB_US,
141 #endif
142 };
143
144 #if NWSMOUSE > 0
145 static int adbkms_enable(void *);
146 static int adbkms_ioctl(void *, u_long, void *, int, struct lwp *);
147 static void adbkms_disable(void *);
148
149 const struct wsmouse_accessops adbkms_accessops = {
150 adbkms_enable,
151 adbkms_ioctl,
152 adbkms_disable,
153 };
154
155 static int adbkbd_sysctl_mid(SYSCTLFN_ARGS);
156 static int adbkbd_sysctl_right(SYSCTLFN_ARGS);
157 static int adbkbd_sysctl_usb(SYSCTLFN_ARGS);
158
159 #endif /* NWSMOUSE > 0 */
160
161 static void adbkbd_setup_sysctl(struct adbkbd_softc *);
162
163 #ifdef ADBKBD_DEBUG
164 #define DPRINTF printf
165 #else
166 #define DPRINTF while (0) printf
167 #endif
168
169 static int adbkbd_is_console = 0;
170 static int adbkbd_console_attached = 0;
171
172 static int
173 adbkbd_match(device_t parent, cfdata_t cf, void *aux)
174 {
175 struct adb_attach_args *aaa = aux;
176
177 if (aaa->dev->original_addr == ADBADDR_KBD)
178 return 1;
179 else
180 return 0;
181 }
182
183 static void
184 adbkbd_attach(device_t parent, device_t self, void *aux)
185 {
186 struct adbkbd_softc *sc = device_private(self);
187 struct adb_attach_args *aaa = aux;
188 short cmd;
189 struct wskbddev_attach_args a;
190 #if NWSMOUSE > 0
191 struct wsmousedev_attach_args am;
192 #endif
193
194 sc->sc_dev = self;
195 sc->sc_ops = aaa->ops;
196 sc->sc_adbdev = aaa->dev;
197 sc->sc_adbdev->cookie = sc;
198 sc->sc_adbdev->handler = adbkbd_handler;
199 sc->sc_us = ADBTALK(sc->sc_adbdev->current_addr, 0);
200
201 sc->sc_leds = 0; /* initially off */
202 sc->sc_have_led_control = 0;
203
204 /*
205 * If this is != 0 then pushing the power button will not immadiately
206 * send a shutdown event to sysmon but instead require another key
207 * press within 5 seconds with a gap of at least two seconds. The
208 * reason to do this is the fact that some PowerBook keyboards,
209 * like the 2400, 3400 and original G3 have their power buttons
210 * right next to the backspace key and it's extremely easy to hit
211 * it by accident.
212 * On most other keyboards the power button is sufficiently far out
213 * of the way so we don't need this.
214 */
215 sc->sc_power_button_delay = 0;
216 sc->sc_msg_len = 0;
217 sc->sc_poll = 0;
218 sc->sc_capslock = 0;
219 sc->sc_trans[1] = 103; /* F11 */
220 sc->sc_trans[2] = 111; /* F12 */
221
222 /*
223 * Most ADB keyboards send 0x7f 0x7f when the power button is pressed.
224 * Some older PowerBooks, like the 3400c, will send a single scancode
225 * 0x7e instead. Unfortunately Fn-Command on some more recent *Books
226 * sends the same scancode, so by default sc_power is set to a value
227 * that can't occur as a scancode and only set to 0x7e on hardware that
228 * needs it
229 */
230 sc->sc_power = 0xffff;
231 sc->sc_timestamp = 0;
232 sc->sc_emul_usb = FALSE;
233
234 printf(" addr %d: ", sc->sc_adbdev->current_addr);
235
236 switch (sc->sc_adbdev->handler_id) {
237 case ADB_STDKBD:
238 printf("standard keyboard\n");
239 break;
240 case ADB_ISOKBD:
241 printf("standard keyboard (ISO layout)\n");
242 break;
243 case ADB_EXTKBD:
244 cmd = ADBTALK(sc->sc_adbdev->current_addr, 1);
245 sc->sc_msg_len = 0;
246 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL);
247 adbkbd_wait(sc, 10);
248
249 /* Ignore Logitech MouseMan/Trackman pseudo keyboard */
250 /* XXX needs testing */
251 if (sc->sc_buffer[2] == 0x9a && sc->sc_buffer[3] == 0x20) {
252 printf("Mouseman (non-EMP) pseudo keyboard\n");
253 return;
254 } else if (sc->sc_buffer[2] == 0x9a &&
255 sc->sc_buffer[3] == 0x21) {
256 printf("Trackman (non-EMP) pseudo keyboard\n");
257 return;
258 } else {
259 printf("extended keyboard\n");
260 adbkbd_initleds(sc);
261 }
262 break;
263 case ADB_EXTISOKBD:
264 printf("extended keyboard (ISO layout)\n");
265 adbkbd_initleds(sc);
266 break;
267 case ADB_KBDII:
268 printf("keyboard II\n");
269 break;
270 case ADB_ISOKBDII:
271 printf("keyboard II (ISO layout)\n");
272 break;
273 case ADB_PBKBD:
274 printf("PowerBook keyboard\n");
275 sc->sc_power = 0x7e;
276 sc->sc_power_button_delay = 1;
277 break;
278 case ADB_PBISOKBD:
279 printf("PowerBook keyboard (ISO layout)\n");
280 sc->sc_power = 0x7e;
281 sc->sc_power_button_delay = 1;
282 break;
283 case ADB_ADJKPD:
284 printf("adjustable keypad\n");
285 break;
286 case ADB_ADJKBD:
287 printf("adjustable keyboard\n");
288 break;
289 case ADB_ADJISOKBD:
290 printf("adjustable keyboard (ISO layout)\n");
291 break;
292 case ADB_ADJJAPKBD:
293 printf("adjustable keyboard (Japanese layout)\n");
294 break;
295 case ADB_PBEXTISOKBD:
296 printf("PowerBook extended keyboard (ISO layout)\n");
297 sc->sc_power_button_delay = 1;
298 sc->sc_power = 0x7e;
299 break;
300 case ADB_PBEXTJAPKBD:
301 printf("PowerBook extended keyboard (Japanese layout)\n");
302 sc->sc_power_button_delay = 1;
303 sc->sc_power = 0x7e;
304 break;
305 case ADB_JPKBDII:
306 printf("keyboard II (Japanese layout)\n");
307 break;
308 case ADB_PBEXTKBD:
309 printf("PowerBook extended keyboard\n");
310 sc->sc_power_button_delay = 1;
311 sc->sc_power = 0x7e;
312 break;
313 case ADB_DESIGNKBD:
314 printf("extended keyboard\n");
315 adbkbd_initleds(sc);
316 break;
317 case ADB_PBJPKBD:
318 printf("PowerBook keyboard (Japanese layout)\n");
319 sc->sc_power_button_delay = 1;
320 sc->sc_power = 0x7e;
321 break;
322 case ADB_PBG3KBD:
323 printf("PowerBook G3 keyboard\n");
324 break;
325 case ADB_PBG3JPKBD:
326 printf("PowerBook G3 keyboard (Japanese layout)\n");
327 break;
328 case ADB_IBOOKKBD:
329 printf("iBook keyboard\n");
330 break;
331 default:
332 printf("mapped device (%d)\n", sc->sc_adbdev->handler_id);
333 break;
334 }
335
336 if (adbkbd_is_console && (adbkbd_console_attached == 0)) {
337 wskbd_cnattach(&adbkbd_consops, sc, &adbkbd_keymapdata);
338 adbkbd_console_attached = 1;
339 a.console = 1;
340 } else {
341 a.console = 0;
342 }
343 a.keymap = &adbkbd_keymapdata;
344 a.accessops = &adbkbd_accessops;
345 a.accesscookie = sc;
346
347 sc->sc_wskbddev = config_found_ia(self, "wskbddev", &a, wskbddevprint);
348 #ifdef ADBKBD_EMUL_USB
349 sc->sc_emul_usb = TRUE;
350 wskbd_set_evtrans(sc->sc_wskbddev, adb_to_usb, 128);
351 #endif /* ADBKBD_EMUL_USB */
352
353 #if NWSMOUSE > 0
354 /* attach the mouse device */
355 am.accessops = &adbkms_accessops;
356 am.accesscookie = sc;
357 sc->sc_wsmousedev = config_found_ia(self, "wsmousedev", &am,
358 wsmousedevprint);
359
360 #endif
361 adbkbd_setup_sysctl(sc);
362
363 /* finally register the power button */
364 sysmon_task_queue_init();
365 memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch));
366 sc->sc_sm_pbutton.smpsw_name = device_xname(sc->sc_dev);
367 sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
368 if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0)
369 aprint_error_dev(sc->sc_dev,
370 "unable to register power button with sysmon\n");
371 }
372
373 static void
374 adbkbd_handler(void *cookie, int len, uint8_t *data)
375 {
376 struct adbkbd_softc *sc = cookie;
377
378 #ifdef ADBKBD_DEBUG
379 int i;
380 printf("%s: %02x - ", device_xname(sc->sc_dev), sc->sc_us);
381 for (i = 0; i < len; i++) {
382 printf(" %02x", data[i]);
383 }
384 printf("\n");
385 #endif
386 if (len >= 2) {
387 if (data[1] == sc->sc_us) {
388 adbkbd_keys(sc, data[2], data[3]);
389 return;
390 } else {
391 memcpy(sc->sc_buffer, data, len);
392 }
393 sc->sc_msg_len = len;
394 wakeup(&sc->sc_event);
395 } else {
396 DPRINTF("bogus message\n");
397 }
398 }
399
400 static int
401 adbkbd_wait(struct adbkbd_softc *sc, int timeout)
402 {
403 int cnt = 0;
404
405 if (sc->sc_poll) {
406 while (sc->sc_msg_len == 0) {
407 sc->sc_ops->poll(sc->sc_ops->cookie);
408 }
409 } else {
410 while ((sc->sc_msg_len == 0) && (cnt < timeout)) {
411 tsleep(&sc->sc_event, 0, "adbkbdio", hz);
412 cnt++;
413 }
414 }
415 return (sc->sc_msg_len > 0);
416 }
417
418 static void
419 adbkbd_keys(struct adbkbd_softc *sc, uint8_t k1, uint8_t k2)
420 {
421
422 /* keyboard event processing */
423
424 DPRINTF("[%02x %02x]", k1, k2);
425
426 if (((k1 == k2) && (k1 == 0x7f)) || (k1 == sc->sc_power)) {
427 uint32_t now = time_second;
428 uint32_t diff = now - sc->sc_timestamp;
429
430 sc->sc_timestamp = now;
431 if (((diff > 1) && (diff < 5)) ||
432 (sc->sc_power_button_delay == 0)) {
433
434 /* power button, report to sysmon */
435 sc->sc_pe = k1;
436 sysmon_task_queue_sched(0, adbkbd_powerbutton, sc);
437 }
438 } else {
439
440 adbkbd_key(sc, k1);
441 if (k2 != 0xff)
442 adbkbd_key(sc, k2);
443 }
444 }
445
446 static void
447 adbkbd_powerbutton(void *cookie)
448 {
449 struct adbkbd_softc *sc = cookie;
450
451 sysmon_pswitch_event(&sc->sc_sm_pbutton,
452 ADBK_PRESS(sc->sc_pe) ? PSWITCH_EVENT_PRESSED :
453 PSWITCH_EVENT_RELEASED);
454 }
455
456 static inline void
457 adbkbd_key(struct adbkbd_softc *sc, uint8_t k)
458 {
459
460 if (sc->sc_poll) {
461 if (sc->sc_polled_chars >= 16) {
462 aprint_error_dev(sc->sc_dev,"polling buffer is full\n");
463 }
464 sc->sc_pollbuf[sc->sc_polled_chars] = k;
465 sc->sc_polled_chars++;
466 return;
467 }
468
469 #if NWSMOUSE > 0
470 /* translate some keys to mouse events */
471 if (sc->sc_wsmousedev != NULL) {
472 if (ADBK_KEYVAL(k) == sc->sc_trans[1]) {
473 wsmouse_input(sc->sc_wsmousedev, ADBK_PRESS(k) ? 2 : 0,
474 0, 0, 0, 0,
475 WSMOUSE_INPUT_DELTA);
476 return;
477 }
478 if (ADBK_KEYVAL(k) == sc->sc_trans[2]) {
479 wsmouse_input(sc->sc_wsmousedev, ADBK_PRESS(k) ? 4 : 0,
480 0, 0, 0, 0,
481 WSMOUSE_INPUT_DELTA);
482 return;
483 }
484 }
485 #endif
486
487 #ifdef WSDISPLAY_COMPAT_RAWKBD
488 if (sc->sc_rawkbd) {
489 char cbuf[2];
490 int s;
491
492 cbuf[0] = k;
493
494 s = spltty();
495 wskbd_rawinput(sc->sc_wskbddev, cbuf, 1);
496 splx(s);
497 } else {
498 #endif
499
500 if (ADBK_KEYVAL(k) == 0x39) {
501 /* caps lock - send up and down */
502 if (ADBK_PRESS(k) != sc->sc_capslock) {
503 sc->sc_capslock = ADBK_PRESS(k);
504 wskbd_input(sc->sc_wskbddev,
505 WSCONS_EVENT_KEY_DOWN, 0x39);
506 wskbd_input(sc->sc_wskbddev,
507 WSCONS_EVENT_KEY_UP, 0x39);
508 }
509 } else {
510 /* normal event */
511 int type;
512
513 type = ADBK_PRESS(k) ?
514 WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
515 wskbd_input(sc->sc_wskbddev, type, ADBK_KEYVAL(k));
516 }
517 #ifdef WSDISPLAY_COMPAT_RAWKBD
518 }
519 #endif
520 }
521
522 /*
523 * Set the keyboard LED's.
524 *
525 * Automatically translates from ioctl/softc format to the
526 * actual keyboard register format
527 */
528 static void
529 adbkbd_set_leds(void *cookie, int leds)
530 {
531 struct adbkbd_softc *sc = cookie;
532 int aleds;
533 short cmd;
534 uint8_t buffer[2];
535
536 DPRINTF("adbkbd_set_leds: %02x\n", leds);
537 if ((leds & 0x07) == (sc->sc_leds & 0x07))
538 return;
539
540 if (sc->sc_have_led_control) {
541
542 aleds = (~leds & 0x04) | 3;
543 if (leds & 1)
544 aleds &= ~2;
545 if (leds & 2)
546 aleds &= ~1;
547
548 buffer[0] = 0xff;
549 buffer[1] = aleds | 0xf8;
550
551 cmd = ADBLISTEN(sc->sc_adbdev->current_addr, 2);
552 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 2,
553 buffer);
554 }
555
556 sc->sc_leds = leds & 7;
557 }
558
559 static void
560 adbkbd_initleds(struct adbkbd_softc *sc)
561 {
562 short cmd;
563
564 /* talk R2 */
565 cmd = ADBTALK(sc->sc_adbdev->current_addr, 2);
566 sc->sc_msg_len = 0;
567 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL);
568 if (!adbkbd_wait(sc, 10)) {
569 printf("unable to read LED state\n");
570 return;
571 }
572 sc->sc_have_led_control = 1;
573 DPRINTF("have LED control\n");
574 return;
575 }
576
577 static int
578 adbkbd_enable(void *v, int on)
579 {
580 return 0;
581 }
582
583 static int
584 adbkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
585 {
586 struct adbkbd_softc *sc = (struct adbkbd_softc *) v;
587
588 switch (cmd) {
589
590 case WSKBDIO_GTYPE:
591 if (sc->sc_emul_usb) {
592 *(int *)data = WSKBD_TYPE_USB;
593 } else {
594 *(int *)data = WSKBD_TYPE_ADB;
595 }
596 return 0;
597 case WSKBDIO_SETLEDS:
598 adbkbd_set_leds(sc, *(int *)data);
599 return 0;
600 case WSKBDIO_GETLEDS:
601 *(int *)data = sc->sc_leds;
602 return 0;
603 #ifdef WSDISPLAY_COMPAT_RAWKBD
604 case WSKBDIO_SETMODE:
605 sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
606 return 0;
607 #endif
608 }
609
610 return EPASSTHROUGH;
611 }
612
613 int
614 adbkbd_cnattach(void)
615 {
616
617 adbkbd_is_console = 1;
618 return 0;
619 }
620
621 static void
622 adbkbd_cngetc(void *v, u_int *type, int *data)
623 {
624 struct adbkbd_softc *sc = v;
625 int key, press, val;
626 int s;
627
628 s = splhigh();
629
630 KASSERT(sc->sc_poll);
631
632 DPRINTF("polling...");
633 while (sc->sc_polled_chars == 0) {
634 sc->sc_ops->poll(sc->sc_ops->cookie);
635 }
636 DPRINTF(" got one\n");
637 splx(s);
638
639 key = sc->sc_pollbuf[0];
640 sc->sc_polled_chars--;
641 memmove(sc->sc_pollbuf, sc->sc_pollbuf + 1,
642 sc->sc_polled_chars);
643
644 press = ADBK_PRESS(key);
645 val = ADBK_KEYVAL(key);
646
647 *data = val;
648 *type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
649 }
650
651 static void
652 adbkbd_cnpollc(void *v, int on)
653 {
654 struct adbkbd_softc *sc = v;
655
656 sc->sc_poll = on;
657 if (!on) {
658 int i;
659
660 /* feed the poll buffer's content to wskbd */
661 for (i = 0; i < sc->sc_polled_chars; i++) {
662 adbkbd_key(sc, sc->sc_pollbuf[i]);
663 }
664 sc->sc_polled_chars = 0;
665 }
666 }
667
668 #if NWSMOUSE > 0
669 /* stuff for the pseudo mouse */
670 static int
671 adbkms_enable(void *v)
672 {
673 return 0;
674 }
675
676 static int
677 adbkms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
678 {
679
680 switch (cmd) {
681 case WSMOUSEIO_GTYPE:
682 *(u_int *)data = WSMOUSE_TYPE_PSEUDO;
683 break;
684
685 default:
686 return (EPASSTHROUGH);
687 }
688 return (0);
689 }
690
691 static void
692 adbkms_disable(void *v)
693 {
694 }
695
696 static int
697 adbkbd_sysctl_mid(SYSCTLFN_ARGS)
698 {
699 struct sysctlnode node = *rnode;
700 struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data;
701 const int *np = newp;
702 int reg;
703
704 DPRINTF("adbkbd_sysctl_mid\n");
705 reg = sc->sc_trans[1];
706 if (np) {
707 /* we're asked to write */
708 node.sysctl_data = ®
709 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
710
711 sc->sc_trans[1] = *(int *)node.sysctl_data;
712 return 0;
713 }
714 return EINVAL;
715 } else {
716 node.sysctl_data = ®
717 node.sysctl_size = 4;
718 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
719 }
720 }
721
722 static int
723 adbkbd_sysctl_right(SYSCTLFN_ARGS)
724 {
725 struct sysctlnode node = *rnode;
726 struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data;
727 const int *np = newp;
728 int reg;
729
730 DPRINTF("adbkbd_sysctl_right\n");
731 reg = sc->sc_trans[2];
732 if (np) {
733 /* we're asked to write */
734 node.sysctl_data = ®
735 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
736
737 sc->sc_trans[2] = *(int *)node.sysctl_data;
738 return 0;
739 }
740 return EINVAL;
741 } else {
742 node.sysctl_data = ®
743 node.sysctl_size = 4;
744 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
745 }
746 }
747
748 #endif /* NWSMOUSE > 0 */
749
750 static int
751 adbkbd_sysctl_usb(SYSCTLFN_ARGS)
752 {
753 struct sysctlnode node = *rnode;
754 struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data;
755 const int *np = newp;
756 bool reg;
757
758 DPRINTF("%s\n", __func__);
759 reg = sc->sc_emul_usb;
760 if (np) {
761 /* we're asked to write */
762 node.sysctl_data = ®
763 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
764
765 sc->sc_emul_usb = *(bool *)node.sysctl_data;
766 if (sc->sc_emul_usb) {
767 wskbd_set_evtrans(sc->sc_wskbddev,
768 adb_to_usb, 128);
769 } else {
770 wskbd_set_evtrans(sc->sc_wskbddev, NULL, 0);
771 }
772 return 0;
773 }
774 return EINVAL;
775 } else {
776 node.sysctl_data = ®
777 node.sysctl_size = sizeof(reg);
778 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
779 }
780 }
781
782 static void
783 adbkbd_setup_sysctl(struct adbkbd_softc *sc)
784 {
785 const struct sysctlnode *me, *node;
786 int ret;
787
788 DPRINTF("%s: sysctl setup\n", device_xname(sc->sc_dev));
789 ret = sysctl_createv(NULL, 0, NULL, &me,
790 CTLFLAG_READWRITE,
791 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
792 NULL, 0, NULL, 0,
793 CTL_MACHDEP, CTL_CREATE, CTL_EOL);
794 ret = sysctl_createv(NULL, 0, NULL,
795 (void *)&node,
796 CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
797 CTLTYPE_BOOL, "emulate_usb", "USB keyboard emulation",
798 adbkbd_sysctl_usb, 1, (void *)sc, 0, CTL_MACHDEP,
799 me->sysctl_num, CTL_CREATE, CTL_EOL);
800 #if NWSMOUSE > 0
801 if (sc->sc_wsmousedev != NULL) {
802 ret = sysctl_createv(NULL, 0, NULL,
803 (void *)&node,
804 CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
805 CTLTYPE_INT, "middle", "middle mouse button",
806 adbkbd_sysctl_mid, 1, (void *)sc, 0, CTL_MACHDEP,
807 me->sysctl_num, CTL_CREATE, CTL_EOL);
808
809 ret = sysctl_createv(NULL, 0, NULL,
810 (void *)&node,
811 CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
812 CTLTYPE_INT, "right", "right mouse button",
813 adbkbd_sysctl_right, 2, (void *)sc, 0, CTL_MACHDEP,
814 me->sysctl_num, CTL_CREATE, CTL_EOL);
815 }
816 #endif /* NWSMOUSE > 0 */
817 }
818
819 SYSCTL_SETUP(sysctl_adbkbdtrans_setup, "adbkbd translator setup")
820 {
821
822 sysctl_createv(NULL, 0, NULL, NULL,
823 CTLFLAG_PERMANENT,
824 CTLTYPE_NODE, "machdep", NULL,
825 NULL, 0, NULL, 0,
826 CTL_MACHDEP, CTL_EOL);
827 }
828