1/* $NetBSD: adb_kbd.c,v 1.15 2011/08/18 02:18:40 christos 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.15 2011/08/18 02:18:40 christos 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 "adbdebug.h" 65#include "wsmouse.h" 66 67struct adbkbd_softc { 68 device_t sc_dev; 69 struct adb_device *sc_adbdev; 70 struct adb_bus_accessops *sc_ops; 71 device_t sc_wskbddev; 72#if NWSMOUSE > 0 73 device_t sc_wsmousedev; 74#endif 75 struct sysmon_pswitch sc_sm_pbutton; 76 int sc_leds; 77 int sc_have_led_control; 78 int sc_power_button_delay; 79 int sc_msg_len; 80 int sc_event; 81 int sc_poll; 82 int sc_polled_chars; 83 int sc_trans[3]; 84 int sc_capslock; 85 uint32_t sc_timestamp; 86#ifdef WSDISPLAY_COMPAT_RAWKBD 87 int sc_rawkbd; 88#endif 89 uint8_t sc_buffer[16]; 90 uint8_t sc_pollbuf[16]; 91 uint8_t sc_us; 92 uint8_t sc_power, sc_pe; 93}; 94 95/* 96 * Function declarations. 97 */ 98static int adbkbd_match(device_t, cfdata_t, void *); 99static void adbkbd_attach(device_t, device_t, void *); 100 101static void adbkbd_initleds(struct adbkbd_softc *); 102static void adbkbd_keys(struct adbkbd_softc *, uint8_t, uint8_t); 103static inline void adbkbd_key(struct adbkbd_softc *, uint8_t); 104static int adbkbd_wait(struct adbkbd_softc *, int); 105 106/* Driver definition. */ 107CFATTACH_DECL_NEW(adbkbd, sizeof(struct adbkbd_softc), 108 adbkbd_match, adbkbd_attach, NULL, NULL); 109 110extern struct cfdriver adbkbd_cd; 111 112static int adbkbd_enable(void *, int); 113static int adbkbd_ioctl(void *, u_long, void *, int, struct lwp *); 114static void adbkbd_set_leds(void *, int); 115static void adbkbd_handler(void *, int, uint8_t *); 116static void adbkbd_powerbutton(void *); 117 118struct wskbd_accessops adbkbd_accessops = { 119 adbkbd_enable, 120 adbkbd_set_leds, 121 adbkbd_ioctl, 122}; 123 124static void adbkbd_cngetc(void *, u_int *, int *); 125static void adbkbd_cnpollc(void *, int); 126 127struct wskbd_consops adbkbd_consops = { 128 adbkbd_cngetc, 129 adbkbd_cnpollc, 130}; 131 132struct wskbd_mapdata adbkbd_keymapdata = { 133 akbd_keydesctab, 134#ifdef AKBD_LAYOUT 135 AKBD_LAYOUT, 136#else 137 KB_US, 138#endif 139}; 140 141#if NWSMOUSE > 0 142static int adbkms_enable(void *); 143static int adbkms_ioctl(void *, u_long, void *, int, struct lwp *); 144static void adbkms_disable(void *); 145 146const struct wsmouse_accessops adbkms_accessops = { 147 adbkms_enable, 148 adbkms_ioctl, 149 adbkms_disable, 150}; 151 152static int adbkbd_sysctl_mid(SYSCTLFN_ARGS); 153static int adbkbd_sysctl_right(SYSCTLFN_ARGS); 154static void adbkbd_setup_sysctl(struct adbkbd_softc *); 155 156#endif /* NWSMOUSE > 0 */ 157 158#ifdef ADBKBD_DEBUG 159#define DPRINTF printf 160#else 161#define DPRINTF while (0) printf 162#endif 163 164static int adbkbd_is_console = 0; 165static int adbkbd_console_attached = 0; 166 167static int 168adbkbd_match(device_t parent, cfdata_t cf, void *aux) 169{ 170 struct adb_attach_args *aaa = aux; 171 172 if (aaa->dev->original_addr == ADBADDR_KBD) 173 return 1; 174 else 175 return 0; 176} 177 178static void 179adbkbd_attach(device_t parent, device_t self, void *aux) 180{ 181 struct adbkbd_softc *sc = device_private(self); 182 struct adb_attach_args *aaa = aux; 183 short cmd; 184 struct wskbddev_attach_args a; 185#if NWSMOUSE > 0 186 struct wsmousedev_attach_args am; 187#endif 188 189 sc->sc_dev = self; 190 sc->sc_ops = aaa->ops; 191 sc->sc_adbdev = aaa->dev; 192 sc->sc_adbdev->cookie = sc; 193 sc->sc_adbdev->handler = adbkbd_handler; 194 sc->sc_us = ADBTALK(sc->sc_adbdev->current_addr, 0); 195 196 sc->sc_leds = 0; /* initially off */ 197 sc->sc_have_led_control = 0; 198 199 /* 200 * If this is != 0 then pushing the power button will not immadiately 201 * send a shutdown event to sysmon but instead require another key 202 * press within 5 seconds with a gap of at least two seconds. The 203 * reason to do this is the fact that some PowerBook keyboards, 204 * like the 2400, 3400 and original G3 have their power buttons 205 * right next to the backspace key and it's extremely easy to hit 206 * it by accident. 207 * On most other keyboards the power button is sufficiently far out 208 * of the way so we don't need this. 209 */ 210 sc->sc_power_button_delay = 0; 211 sc->sc_msg_len = 0; 212 sc->sc_poll = 0; 213 sc->sc_capslock = 0; 214 sc->sc_trans[1] = 103; /* F11 */ 215 sc->sc_trans[2] = 111; /* F12 */ 216 sc->sc_power = 0x7f; 217 sc->sc_timestamp = 0; 218 219 printf(" addr %d: ", sc->sc_adbdev->current_addr); 220 221 switch (sc->sc_adbdev->handler_id) { 222 case ADB_STDKBD: 223 printf("standard keyboard\n"); 224 break; 225 case ADB_ISOKBD: 226 printf("standard keyboard (ISO layout)\n"); 227 break; 228 case ADB_EXTKBD: 229 cmd = ADBTALK(sc->sc_adbdev->current_addr, 1); 230 sc->sc_msg_len = 0; 231 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL); 232 adbkbd_wait(sc, 10); 233 234 /* Ignore Logitech MouseMan/Trackman pseudo keyboard */ 235 /* XXX needs testing */ 236 if (sc->sc_buffer[2] == 0x9a && sc->sc_buffer[3] == 0x20) { 237 printf("Mouseman (non-EMP) pseudo keyboard\n"); 238 return; 239 } else if (sc->sc_buffer[2] == 0x9a && 240 sc->sc_buffer[3] == 0x21) { 241 printf("Trackman (non-EMP) pseudo keyboard\n"); 242 return; 243 } else { 244 printf("extended keyboard\n"); 245 adbkbd_initleds(sc); 246 } 247 break; 248 case ADB_EXTISOKBD: 249 printf("extended keyboard (ISO layout)\n"); 250 adbkbd_initleds(sc); 251 break; 252 case ADB_KBDII: 253 printf("keyboard II\n"); 254 break; 255 case ADB_ISOKBDII: 256 printf("keyboard II (ISO layout)\n"); 257 break; 258 case ADB_PBKBD: 259 printf("PowerBook keyboard\n"); 260 sc->sc_power = 0x7e; 261 sc->sc_power_button_delay = 1; 262 break; 263 case ADB_PBISOKBD: 264 printf("PowerBook keyboard (ISO layout)\n"); 265 sc->sc_power = 0x7e; 266 sc->sc_power_button_delay = 1; 267 break; 268 case ADB_ADJKPD: 269 printf("adjustable keypad\n"); 270 break; 271 case ADB_ADJKBD: 272 printf("adjustable keyboard\n"); 273 break; 274 case ADB_ADJISOKBD: 275 printf("adjustable keyboard (ISO layout)\n"); 276 break; 277 case ADB_ADJJAPKBD: 278 printf("adjustable keyboard (Japanese layout)\n"); 279 break; 280 case ADB_PBEXTISOKBD: 281 printf("PowerBook extended keyboard (ISO layout)\n"); 282 sc->sc_power_button_delay = 1; 283 sc->sc_power = 0x7e; 284 break; 285 case ADB_PBEXTJAPKBD: 286 printf("PowerBook extended keyboard (Japanese layout)\n"); 287 sc->sc_power_button_delay = 1; 288 sc->sc_power = 0x7e; 289 break; 290 case ADB_JPKBDII: 291 printf("keyboard II (Japanese layout)\n"); 292 break; 293 case ADB_PBEXTKBD: 294 printf("PowerBook extended keyboard\n"); 295 sc->sc_power_button_delay = 1; 296 sc->sc_power = 0x7e; 297 break; 298 case ADB_DESIGNKBD: 299 printf("extended keyboard\n"); 300 adbkbd_initleds(sc); 301 break; 302 case ADB_PBJPKBD: 303 printf("PowerBook keyboard (Japanese layout)\n"); 304 sc->sc_power_button_delay = 1; 305 sc->sc_power = 0x7e; 306 break; 307 case ADB_PBG3KBD: 308 printf("PowerBook G3 keyboard\n"); 309 sc->sc_power = 0x7e; 310 break; 311 case ADB_PBG3JPKBD: 312 printf("PowerBook G3 keyboard (Japanese layout)\n"); 313 sc->sc_power = 0x7e; 314 break; 315 case ADB_IBOOKKBD: 316 printf("iBook keyboard\n"); 317 break; 318 default: 319 printf("mapped device (%d)\n", sc->sc_adbdev->handler_id); 320 break; 321 } 322 323 if (adbkbd_is_console && (adbkbd_console_attached == 0)) { 324 wskbd_cnattach(&adbkbd_consops, sc, &adbkbd_keymapdata); 325 adbkbd_console_attached = 1; 326 a.console = 1; 327 } else { 328 a.console = 0; 329 } 330 a.keymap = &adbkbd_keymapdata; 331 a.accessops = &adbkbd_accessops; 332 a.accesscookie = sc; 333 334 sc->sc_wskbddev = config_found_ia(self, "wskbddev", &a, wskbddevprint); 335 336#if NWSMOUSE > 0 337 /* attach the mouse device */ 338 am.accessops = &adbkms_accessops; 339 am.accesscookie = sc; 340 sc->sc_wsmousedev = config_found_ia(self, "wsmousedev", &am, 341 wsmousedevprint); 342 343 if (sc->sc_wsmousedev != NULL) 344 adbkbd_setup_sysctl(sc); 345#endif 346 347 /* finally register the power button */ 348 sysmon_task_queue_init(); 349 memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch)); 350 sc->sc_sm_pbutton.smpsw_name = device_xname(sc->sc_dev); 351 sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER; 352 if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0) 353 aprint_error_dev(sc->sc_dev, 354 "unable to register power button with sysmon\n"); 355} 356 357static void 358adbkbd_handler(void *cookie, int len, uint8_t *data) 359{ 360 struct adbkbd_softc *sc = cookie; 361 362#ifdef ADBKBD_DEBUG 363 int i; 364 printf("%s: %02x - ", device_xname(sc->sc_dev), sc->sc_us); 365 for (i = 0; i < len; i++) { 366 printf(" %02x", data[i]); 367 } 368 printf("\n"); 369#endif 370 if (len >= 2) { 371 if (data[1] == sc->sc_us) { 372 adbkbd_keys(sc, data[2], data[3]); 373 return; 374 } else { 375 memcpy(sc->sc_buffer, data, len); 376 } 377 sc->sc_msg_len = len; 378 wakeup(&sc->sc_event); 379 } else { 380 DPRINTF("bogus message\n"); 381 } 382} 383 384static int 385adbkbd_wait(struct adbkbd_softc *sc, int timeout) 386{ 387 int cnt = 0; 388 389 if (sc->sc_poll) { 390 while (sc->sc_msg_len == 0) { 391 sc->sc_ops->poll(sc->sc_ops->cookie); 392 } 393 } else { 394 while ((sc->sc_msg_len == 0) && (cnt < timeout)) { 395 tsleep(&sc->sc_event, 0, "adbkbdio", hz); 396 cnt++; 397 } 398 } 399 return (sc->sc_msg_len > 0); 400} 401 402static void 403adbkbd_keys(struct adbkbd_softc *sc, uint8_t k1, uint8_t k2) 404{ 405 406 /* keyboard event processing */ 407 408 DPRINTF("[%02x %02x]", k1, k2); 409 410 if (((k1 == k2) && (k1 == 0x7f)) || (k1 == sc->sc_power)) { 411 uint32_t now = time_second; 412 uint32_t diff = now - sc->sc_timestamp; 413 414 sc->sc_timestamp = now; 415 if (((diff > 1) && (diff < 5)) || 416 (sc->sc_power_button_delay == 0)) { 417 418 /* power button, report to sysmon */ 419 sc->sc_pe = k1; 420 421 sysmon_task_queue_sched(0, adbkbd_powerbutton, sc); 422 } 423 } else { 424 425 adbkbd_key(sc, k1); 426 if (k2 != 0xff) 427 adbkbd_key(sc, k2); 428 } 429} 430 431static void 432adbkbd_powerbutton(void *cookie) 433{ 434 struct adbkbd_softc *sc = cookie; 435 436 sysmon_pswitch_event(&sc->sc_sm_pbutton, 437 ADBK_PRESS(sc->sc_pe) ? PSWITCH_EVENT_PRESSED : 438 PSWITCH_EVENT_RELEASED); 439} 440 441static inline void 442adbkbd_key(struct adbkbd_softc *sc, uint8_t k) 443{ 444 445 if (sc->sc_poll) { 446 if (sc->sc_polled_chars >= 16) { 447 aprint_error_dev(sc->sc_dev,"polling buffer is full\n"); 448 } 449 sc->sc_pollbuf[sc->sc_polled_chars] = k; 450 sc->sc_polled_chars++; 451 return; 452 } 453 454#if NWSMOUSE > 0 455 /* translate some keys to mouse events */ 456 if (sc->sc_wsmousedev != NULL) { 457 if (ADBK_KEYVAL(k) == sc->sc_trans[1]) { 458 wsmouse_input(sc->sc_wsmousedev, ADBK_PRESS(k) ? 2 : 0, 459 0, 0, 0, 0, 460 WSMOUSE_INPUT_DELTA); 461 return; 462 } 463 if (ADBK_KEYVAL(k) == sc->sc_trans[2]) { 464 wsmouse_input(sc->sc_wsmousedev, ADBK_PRESS(k) ? 4 : 0, 465 0, 0, 0, 0, 466 WSMOUSE_INPUT_DELTA); 467 return; 468 } 469 } 470#endif 471 472#ifdef WSDISPLAY_COMPAT_RAWKBD 473 if (sc->sc_rawkbd) { 474 char cbuf[2]; 475 int s; 476 477 cbuf[0] = k; 478 479 s = spltty(); 480 wskbd_rawinput(sc->sc_wskbddev, cbuf, 1); 481 splx(s); 482 } else { 483#endif 484 485 if (ADBK_KEYVAL(k) == 0x39) { 486 /* caps lock - send up and down */ 487 if (ADBK_PRESS(k) != sc->sc_capslock) { 488 sc->sc_capslock = ADBK_PRESS(k); 489 wskbd_input(sc->sc_wskbddev, 490 WSCONS_EVENT_KEY_DOWN, 0x39); 491 wskbd_input(sc->sc_wskbddev, 492 WSCONS_EVENT_KEY_UP, 0x39); 493 } 494 } else { 495 /* normal event */ 496 int type; 497 498 type = ADBK_PRESS(k) ? 499 WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP; 500 wskbd_input(sc->sc_wskbddev, type, ADBK_KEYVAL(k)); 501 } 502#ifdef WSDISPLAY_COMPAT_RAWKBD 503 } 504#endif 505} 506 507/* 508 * Set the keyboard LED's. 509 * 510 * Automatically translates from ioctl/softc format to the 511 * actual keyboard register format 512 */ 513static void 514adbkbd_set_leds(void *cookie, int leds) 515{ 516 struct adbkbd_softc *sc = cookie; 517 int aleds; 518 short cmd; 519 uint8_t buffer[2]; 520 521 DPRINTF("adbkbd_set_leds: %02x\n", leds); 522 if ((leds & 0x07) == (sc->sc_leds & 0x07)) 523 return; 524 525 if (sc->sc_have_led_control) { 526 527 aleds = (~leds & 0x04) | 3; 528 if (leds & 1) 529 aleds &= ~2; 530 if (leds & 2) 531 aleds &= ~1; 532 533 buffer[0] = 0xff; 534 buffer[1] = aleds | 0xf8; 535 536 cmd = ADBLISTEN(sc->sc_adbdev->current_addr, 2); 537 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 2, 538 buffer); 539 } 540 541 sc->sc_leds = leds & 7; 542} 543 544static void 545adbkbd_initleds(struct adbkbd_softc *sc) 546{ 547 short cmd; 548 549 /* talk R2 */ 550 cmd = ADBTALK(sc->sc_adbdev->current_addr, 2); 551 sc->sc_msg_len = 0; 552 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL); 553 if (!adbkbd_wait(sc, 10)) { 554 printf("unable to read LED state\n"); 555 return; 556 } 557 sc->sc_have_led_control = 1; 558 DPRINTF("have LED control\n"); 559 return; 560} 561 562static int 563adbkbd_enable(void *v, int on) 564{ 565 return 0; 566} 567 568static int 569adbkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 570{ 571 struct adbkbd_softc *sc = (struct adbkbd_softc *) v; 572 573 switch (cmd) { 574 575 case WSKBDIO_GTYPE: 576 *(int *)data = WSKBD_TYPE_ADB; 577 return 0; 578 case WSKBDIO_SETLEDS: 579 adbkbd_set_leds(sc, *(int *)data); 580 return 0; 581 case WSKBDIO_GETLEDS: 582 *(int *)data = sc->sc_leds; 583 return 0; 584#ifdef WSDISPLAY_COMPAT_RAWKBD 585 case WSKBDIO_SETMODE: 586 sc->sc_rawkbd = *(int *)data == WSKBD_RAW; 587 return 0; 588#endif 589 } 590 591 return EPASSTHROUGH; 592} 593 594int 595adbkbd_cnattach(void) 596{ 597 598 adbkbd_is_console = 1; 599 return 0; 600} 601 602static void 603adbkbd_cngetc(void *v, u_int *type, int *data) 604{ 605 struct adbkbd_softc *sc = v; 606 int key, press, val; 607 int s; 608 609 s = splhigh(); 610 611 KASSERT(sc->sc_poll); 612 613 DPRINTF("polling..."); 614 while (sc->sc_polled_chars == 0) { 615 sc->sc_ops->poll(sc->sc_ops->cookie); 616 } 617 DPRINTF(" got one\n"); 618 splx(s); 619 620 key = sc->sc_pollbuf[0]; 621 sc->sc_polled_chars--; 622 memmove(sc->sc_pollbuf, sc->sc_pollbuf + 1, 623 sc->sc_polled_chars); 624 625 press = ADBK_PRESS(key); 626 val = ADBK_KEYVAL(key); 627 628 *data = val; 629 *type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP; 630} 631 632static void 633adbkbd_cnpollc(void *v, int on) 634{ 635 struct adbkbd_softc *sc = v; 636 637 sc->sc_poll = on; 638 if (!on) { 639 int i; 640 641 /* feed the poll buffer's content to wskbd */ 642 for (i = 0; i < sc->sc_polled_chars; i++) { 643 adbkbd_key(sc, sc->sc_pollbuf[i]); 644 } 645 sc->sc_polled_chars = 0; 646 } 647} 648 649#if NWSMOUSE > 0 650/* stuff for the pseudo mouse */ 651static int 652adbkms_enable(void *v) 653{ 654 return 0; 655} 656 657static int 658adbkms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 659{ 660 661 switch (cmd) { 662 case WSMOUSEIO_GTYPE: 663 *(u_int *)data = WSMOUSE_TYPE_PSEUDO; 664 break; 665 666 default: 667 return (EPASSTHROUGH); 668 } 669 return (0); 670} 671 672static void 673adbkms_disable(void *v) 674{ 675} 676 677static void 678adbkbd_setup_sysctl(struct adbkbd_softc *sc) 679{ 680 const struct sysctlnode *me, *node; 681 int ret; 682 683 DPRINTF("%s: sysctl setup\n", device_xname(sc->sc_dev)); 684 ret = sysctl_createv(NULL, 0, NULL, &me, 685 CTLFLAG_READWRITE, 686 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, 687 NULL, 0, NULL, 0, 688 CTL_MACHDEP, CTL_CREATE, CTL_EOL); 689 690 ret = sysctl_createv(NULL, 0, NULL, 691 (void *)&node, 692 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 693 CTLTYPE_INT, "middle", "middle mouse button", adbkbd_sysctl_mid, 694 1, sc, 0, CTL_MACHDEP, me->sysctl_num, CTL_CREATE, 695 CTL_EOL); 696 697 ret = sysctl_createv(NULL, 0, NULL, 698 (void *)&node, 699 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 700 CTLTYPE_INT, "right", "right mouse button", adbkbd_sysctl_right, 701 2, sc, 0, CTL_MACHDEP, me->sysctl_num, CTL_CREATE, 702 CTL_EOL); 703} 704 705static int 706adbkbd_sysctl_mid(SYSCTLFN_ARGS) 707{ 708 struct sysctlnode node = *rnode; 709 struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data; 710 const int *np = newp; 711 int reg; 712 713 DPRINTF("adbkbd_sysctl_mid\n"); 714 reg = sc->sc_trans[1]; 715 if (np) { 716 /* we're asked to write */ 717 node.sysctl_data = ® 718 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 719 720 sc->sc_trans[1] = *(int *)node.sysctl_data; 721 return 0; 722 } 723 return EINVAL; 724 } else { 725 node.sysctl_data = ® 726 node.sysctl_size = 4; 727 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 728 } 729} 730 731static int 732adbkbd_sysctl_right(SYSCTLFN_ARGS) 733{ 734 struct sysctlnode node = *rnode; 735 struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data; 736 const int *np = newp; 737 int reg; 738 739 DPRINTF("adbkbd_sysctl_right\n"); 740 reg = sc->sc_trans[2]; 741 if (np) { 742 /* we're asked to write */ 743 node.sysctl_data = ® 744 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 745 746 sc->sc_trans[2] = *(int *)node.sysctl_data; 747 return 0; 748 } 749 return EINVAL; 750 } else { 751 node.sysctl_data = ® 752 node.sysctl_size = 4; 753 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 754 } 755} 756 757SYSCTL_SETUP(sysctl_adbkbdtrans_setup, "adbkbd translator setup") 758{ 759 760 sysctl_createv(NULL, 0, NULL, NULL, 761 CTLFLAG_PERMANENT, 762 CTLTYPE_NODE, "machdep", NULL, 763 NULL, 0, NULL, 0, 764 CTL_MACHDEP, CTL_EOL); 765} 766#endif /* NWSMOUSE > 0 */ 767