The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/adb/adb_kbd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: adb_kbd.c,v 1.33 2022/05/14 01:16:55 manu 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.33 2022/05/14 01:16:55 manu Exp $");
   36 
   37 #ifdef _KERNEL_OPT
   38 #include "opt_ddb.h"
   39 #endif
   40 
   41 #include <sys/param.h>
   42 #include <sys/device.h>
   43 #include <sys/fcntl.h>
   44 #include <sys/poll.h>
   45 #include <sys/select.h>
   46 #include <sys/proc.h>
   47 #include <sys/systm.h>
   48 #include <sys/kernel.h>
   49 #include <sys/sysctl.h>
   50 
   51 #include <dev/wscons/wsconsio.h>
   52 #include <dev/wscons/wskbdvar.h>
   53 #include <dev/wscons/wsksymdef.h>
   54 #include <dev/wscons/wsksymvar.h>
   55 #include <dev/wscons/wsmousevar.h>
   56 
   57 #include <dev/sysmon/sysmonvar.h>
   58 #include <dev/sysmon/sysmon_taskq.h>
   59 
   60 #include <machine/autoconf.h>
   61 #include <machine/keyboard.h>
   62 #include <machine/adbsys.h>
   63 
   64 #include <dev/adb/adbvar.h>
   65 #include <dev/adb/adb_keymap.h>
   66 
   67 #include "ioconf.h"
   68 
   69 #include "opt_wsdisplay_compat.h"
   70 #include "opt_adbkbd.h"
   71 #include "adbdebug.h"
   72 #include "wsmouse.h"
   73 
   74 struct adbkbd_softc {
   75         device_t sc_dev;
   76         struct adb_device *sc_adbdev;
   77         struct adb_bus_accessops *sc_ops;
   78         device_t sc_wskbddev;
   79 #if NWSMOUSE > 0
   80         device_t sc_wsmousedev;
   81 #endif
   82         struct sysmon_pswitch sc_sm_pbutton;
   83         int sc_leds;
   84         int sc_have_led_control;
   85         int sc_power_button_delay;
   86         int sc_msg_len;
   87         int sc_event;
   88         int sc_poll;
   89         int sc_polled_chars;
   90         int sc_trans[3];
   91         int sc_capslock;
   92         uint32_t sc_timestamp;
   93 #ifdef WSDISPLAY_COMPAT_RAWKBD
   94         int sc_rawkbd;
   95 #endif
   96         int sc_emul_usb;
   97         bool sc_power_dbg;
   98 
   99         uint32_t sc_power;
  100         uint8_t sc_buffer[16];
  101         uint8_t sc_pollbuf[16];
  102         uint8_t sc_us, sc_pe;
  103 };      
  104 
  105 /*
  106  * Function declarations.
  107  */
  108 static int      adbkbd_match(device_t, cfdata_t, void *);
  109 static void     adbkbd_attach(device_t, device_t, void *);
  110 
  111 static void     adbkbd_initleds(struct adbkbd_softc *);
  112 static void     adbkbd_keys(struct adbkbd_softc *, uint8_t, uint8_t);
  113 static inline void adbkbd_key(struct adbkbd_softc *, uint8_t);
  114 static int      adbkbd_wait(struct adbkbd_softc *, int);
  115 
  116 /* Driver definition. */
  117 CFATTACH_DECL_NEW(adbkbd, sizeof(struct adbkbd_softc),
  118     adbkbd_match, adbkbd_attach, NULL, NULL);
  119 
  120 static int adbkbd_enable(void *, int);
  121 static int adbkbd_ioctl(void *, u_long, void *, int, struct lwp *);
  122 static void adbkbd_set_leds(void *, int);
  123 static void adbkbd_handler(void *, int, uint8_t *);
  124 static void adbkbd_powerbutton(void *);
  125 
  126 struct wskbd_accessops adbkbd_accessops = {
  127         adbkbd_enable,
  128         adbkbd_set_leds,
  129         adbkbd_ioctl,
  130 };
  131 
  132 static void adbkbd_cngetc(void *, u_int *, int *);
  133 static void adbkbd_cnpollc(void *, int);
  134 
  135 struct wskbd_consops adbkbd_consops = {
  136         adbkbd_cngetc,
  137         adbkbd_cnpollc,
  138 };
  139 
  140 struct wskbd_mapdata adbkbd_keymapdata = {
  141         akbd_keydesctab,
  142 #ifdef ADBKBD_LAYOUT
  143         ADBKBD_LAYOUT,
  144 #else
  145         KB_US | KB_APPLE,
  146 #endif
  147 };
  148 
  149 #if NWSMOUSE > 0
  150 static int adbkms_enable(void *);
  151 static int adbkms_ioctl(void *, u_long, void *, int, struct lwp *);
  152 static void adbkms_disable(void *);
  153 
  154 const struct wsmouse_accessops adbkms_accessops = {
  155         adbkms_enable,
  156         adbkms_ioctl,
  157         adbkms_disable,
  158 };
  159 
  160 static int  adbkbd_sysctl_mid(SYSCTLFN_ARGS);
  161 static int  adbkbd_sysctl_right(SYSCTLFN_ARGS);
  162 static int  adbkbd_sysctl_usb(SYSCTLFN_ARGS);
  163 
  164 #endif /* NWSMOUSE > 0 */
  165 
  166 static void adbkbd_setup_sysctl(struct adbkbd_softc *);
  167 
  168 #ifdef ADBKBD_DEBUG
  169 #define DPRINTF printf
  170 #else
  171 #define DPRINTF while (0) printf
  172 #endif
  173 
  174 static int adbkbd_is_console = 0;
  175 static int adbkbd_console_attached = 0;
  176 
  177 static int
  178 adbkbd_match(device_t parent, cfdata_t cf, void *aux)
  179 {
  180         struct adb_attach_args *aaa = aux;
  181 
  182         if (aaa->dev->original_addr == ADBADDR_KBD)
  183                 return 1;
  184         else
  185                 return 0;
  186 }
  187 
  188 static void
  189 adbkbd_attach(device_t parent, device_t self, void *aux)
  190 {
  191         struct adbkbd_softc *sc = device_private(self);
  192         struct adb_attach_args *aaa = aux;
  193         short cmd;
  194         struct wskbddev_attach_args a;
  195 #if NWSMOUSE > 0
  196         struct wsmousedev_attach_args am;
  197 #endif
  198         uint8_t buffer[2];
  199 
  200         sc->sc_dev = self;
  201         sc->sc_ops = aaa->ops;
  202         sc->sc_adbdev = aaa->dev;
  203         sc->sc_adbdev->cookie = sc;
  204         sc->sc_adbdev->handler = adbkbd_handler;
  205         sc->sc_us = ADBTALK(sc->sc_adbdev->current_addr, 0);
  206 
  207         sc->sc_leds = 0;        /* initially off */
  208         sc->sc_have_led_control = 0;
  209 
  210         /*
  211          * If this is != 0 then pushing the power button will not immadiately
  212          * send a shutdown event to sysmon but instead require another key
  213          * press within 5 seconds with a gap of at least two seconds. The 
  214          * reason to do this is the fact that some PowerBook keyboards,
  215          * like the 2400, 3400 and original G3 have their power buttons
  216          * right next to the backspace key and it's extremely easy to hit
  217          * it by accident.
  218          * On most other keyboards the power button is sufficiently far out
  219          * of the way so we don't need this.
  220          */
  221         sc->sc_power_button_delay = 0;
  222         sc->sc_msg_len = 0;
  223         sc->sc_poll = 0;
  224         sc->sc_capslock = 0;
  225         sc->sc_trans[1] = 103;  /* F11 */
  226         sc->sc_trans[2] = 111;  /* F12 */
  227         
  228         /*
  229          * Most ADB keyboards send 0x7f 0x7f when the power button is pressed.
  230          * Some older PowerBooks, like the 3400c, will send a single scancode
  231          * 0x7e instead. Unfortunately Fn-Command on some more recent *Books
  232          * sends the same scancode, so by default sc_power is set to a value
  233          * that can't occur as a scancode and only set to 0x7e on hardware that
  234          * needs it
  235          */
  236         sc->sc_power = 0xffff;
  237         sc->sc_timestamp = 0;
  238         sc->sc_emul_usb = ADB_EMUL_USB_NONE;
  239 #ifdef ADBKBD_POWER_DDB
  240         sc->sc_power_dbg = TRUE;
  241 #else
  242         sc->sc_power_dbg = FALSE;
  243 #endif
  244 
  245         aprint_normal(" addr %d: ", sc->sc_adbdev->current_addr);
  246 
  247         switch (sc->sc_adbdev->handler_id) {
  248         case ADB_STDKBD:
  249                 aprint_normal("standard keyboard\n");
  250                 break;
  251         case ADB_ISOKBD:
  252                 aprint_normal("standard keyboard (ISO layout)\n");
  253                 break;
  254         case ADB_EXTKBD:
  255                 cmd = ADBTALK(sc->sc_adbdev->current_addr, 1);
  256                 sc->sc_msg_len = 0;
  257                 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL);
  258                 adbkbd_wait(sc, 10);
  259 
  260                 /* Ignore Logitech MouseMan/Trackman pseudo keyboard */
  261                 /* XXX needs testing */
  262                 if (sc->sc_buffer[2] == 0x9a && sc->sc_buffer[3] == 0x20) {
  263                         aprint_normal("Mouseman (non-EMP) pseudo keyboard\n");
  264                         return;
  265                 } else if (sc->sc_buffer[2] == 0x9a && 
  266                     sc->sc_buffer[3] == 0x21) {
  267                         aprint_normal("Trackman (non-EMP) pseudo keyboard\n");
  268                         return;
  269                 } else {
  270                         aprint_normal("extended keyboard\n");
  271                         adbkbd_initleds(sc);
  272                 }
  273                 break;
  274         case ADB_EXTISOKBD:
  275                 aprint_normal("extended keyboard (ISO layout)\n");
  276                 adbkbd_initleds(sc);
  277                 break;
  278         case ADB_KBDII:
  279                 aprint_normal("keyboard II\n");
  280                 break;
  281         case ADB_ISOKBDII:
  282                 aprint_normal("keyboard II (ISO layout)\n");
  283                 break;
  284         case ADB_PBKBD:
  285                 aprint_normal("PowerBook keyboard\n");
  286                 sc->sc_power = 0x7e;
  287                 sc->sc_power_button_delay = 1;
  288                 break;
  289         case ADB_PBISOKBD:
  290                 aprint_normal("PowerBook keyboard (ISO layout)\n");
  291                 sc->sc_power = 0x7e;
  292                 sc->sc_power_button_delay = 1;
  293                 break;
  294         case ADB_ADJKPD:
  295                 aprint_normal("adjustable keypad\n");
  296                 break;
  297         case ADB_ADJKBD:
  298                 aprint_normal("adjustable keyboard\n");
  299                 break;
  300         case ADB_ADJISOKBD:
  301                 aprint_normal("adjustable keyboard (ISO layout)\n");
  302                 break;
  303         case ADB_ADJJAPKBD:
  304                 aprint_normal("adjustable keyboard (Japanese layout)\n");
  305                 break;
  306         case ADB_PBEXTISOKBD:
  307                 aprint_normal("PowerBook extended keyboard (ISO layout)\n");
  308                 sc->sc_power_button_delay = 1;
  309                 sc->sc_power = 0x7e;
  310                 break;
  311         case ADB_PBEXTJAPKBD:
  312                 aprint_normal("PowerBook extended keyboard (Japanese layout)\n");
  313                 sc->sc_power_button_delay = 1;
  314                 sc->sc_power = 0x7e;
  315                 break;
  316         case ADB_JPKBDII:
  317                 aprint_normal("keyboard II (Japanese layout)\n");
  318                 break;
  319         case ADB_PBEXTKBD:
  320                 aprint_normal("PowerBook extended keyboard\n");
  321                 sc->sc_power_button_delay = 1;
  322                 sc->sc_power = 0x7e;
  323                 break;
  324         case ADB_DESIGNKBD:
  325                 aprint_normal("extended keyboard\n");
  326                 adbkbd_initleds(sc);
  327                 break;
  328         case ADB_PBJPKBD:
  329                 aprint_normal("PowerBook keyboard (Japanese layout)\n");
  330                 sc->sc_power_button_delay = 1;
  331                 sc->sc_power = 0x7e;
  332                 break;
  333         case ADB_PBG3KBD:
  334                 aprint_normal("PowerBook G3 keyboard\n");
  335                 break;
  336         case ADB_PBG3JPKBD:
  337                 aprint_normal("PowerBook G3 keyboard (Japanese layout)\n");
  338                 break;
  339         case ADB_IBOOKKBD:
  340                 aprint_normal("iBook keyboard\n");
  341                 break;
  342         default:
  343                 aprint_normal("mapped device (%d)\n", sc->sc_adbdev->handler_id);
  344                 break;
  345         }
  346 
  347         /*
  348          * try to switch to extended protocol
  349          * as in, tell the keyboard to distinguish between left and right
  350          * Shift, Control and Alt keys
  351          */
  352         cmd = ADBLISTEN(sc->sc_adbdev->current_addr, 3);
  353         buffer[0] = sc->sc_adbdev->current_addr;
  354         buffer[1] = 3;
  355         sc->sc_msg_len = 0;
  356         sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 2, buffer);
  357         adbkbd_wait(sc, 10);
  358 
  359         cmd = ADBTALK(sc->sc_adbdev->current_addr, 3);
  360         sc->sc_msg_len = 0;
  361         sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL);
  362         adbkbd_wait(sc, 10);
  363         if ((sc->sc_msg_len == 4) && (sc->sc_buffer[3] == 3)) {
  364                 aprint_verbose_dev(sc->sc_dev, "extended protocol enabled\n");
  365         }
  366 
  367 #ifdef ADBKBD_DEBUG
  368         cmd = ADBTALK(sc->sc_adbdev->current_addr, 1);
  369         sc->sc_msg_len = 0;
  370         sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL);
  371         adbkbd_wait(sc, 10);
  372         printf("buffer: %02x %02x\n", sc->sc_buffer[0], sc->sc_buffer[1]);
  373 #endif
  374 
  375         if (adbkbd_is_console && (adbkbd_console_attached == 0)) {
  376                 wskbd_cnattach(&adbkbd_consops, sc, &adbkbd_keymapdata);
  377                 adbkbd_console_attached = 1;
  378                 a.console = 1;
  379         } else {
  380                 a.console = 0;
  381         }
  382         a.keymap = &adbkbd_keymapdata;
  383         a.accessops = &adbkbd_accessops;
  384         a.accesscookie = sc;
  385 
  386         sc->sc_wskbddev = config_found(self, &a, wskbddevprint,
  387             CFARGS(.iattr = "wskbddev"));
  388 #ifdef ADBKBD_EMUL_USB
  389         /* Values from Linux's drivers/macintosh/adbhud.c */
  390         switch (sc->sc_adbdev->handler_id) {
  391         case ADB_ISOKBD:        /* FALLTHROUGH */
  392         case ADB_EXTISOKBD:     /* FALLTHROUGH */
  393         case 0x07:              /* FALLTHROUGH */
  394         case ADB_ISOKBDII:      /* FALLTHROUGH */
  395         case ADB_PBISOKBD:      /* FALLTHROUGH */
  396         case ADB_ADJISOKBD:     /* FALLTHROUGH */
  397         case ADB_PBEXTISOKBD:   /* FALLTHROUGH */
  398         case 0x19:              /* FALLTHROUGH */
  399         case 0x1d:              /* FALLTHROUGH */
  400         case 0xc1:              /* FALLTHROUGH */
  401         case ADB_IBOOKKBD:      /* FALLTHROUGH */
  402         case 0xc7:
  403                 sc->sc_emul_usb = ADB_EMUL_USB_ISO;
  404                 wskbd_set_evtrans(sc->sc_wskbddev, adb_to_usb_iso, 128);
  405                 break;
  406 #ifdef notyet
  407         case ADB_ADJJAPKBD:     /* FALLTHROUGH */
  408         case ADB_PBEXTJAPKBD:   /* FALLTHROUGH */
  409         case ADB_JPKBDII:       /* FALLTHROUGH */
  410         case 0x17:              /* FALLTHROUGH */
  411         case 0x1a:              /* FALLTHROUGH */
  412         case ADB_PBJPKBD:       /* FALLTHROUGH */
  413         case 0xc2:              /* FALLTHROUGH */
  414         case 0xc5:              /* FALLTHROUGH */
  415         case 0xc8:              /* FALLTHROUGH */
  416         case 0xc9:
  417                 sc->sc_emul_usb = ADB_EMUL_USB_JIS;
  418                 wskbd_set_evtrans(sc->sc_wskbddev, adb_to_usb_jis, 128);
  419                 break;
  420 #endif
  421         case ADB_STDKBD:        /* FALLTHROUGH */
  422         case ADB_EXTKBD:        /* FALLTHROUGH */
  423         case 0x03:              /* FALLTHROUGH */
  424         case 0x06:              /* FALLTHROUGH */
  425         case ADB_KBDII:         /* FALLTHROUGH */
  426         case ADB_PBKBD:         /* FALLTHROUGH */
  427         case ADB_ADJKBD:        /* FALLTHROUGH */
  428         case ADB_PBEXTKBD:      /* FALLTHROUGH */
  429         case ADB_DESIGNKBD:     /* FALLTHROUGH */
  430         case 0x1c:              /* FALLTHROUGH */
  431         case 0xc0:              /* FALLTHROUGH */
  432         case ADB_PBG3KBD:       /* FALLTHROUGH */
  433         case 0xc6:              /* FALLTHROUGH */
  434         default:        /* default to ANSI for unknown values */
  435                 sc->sc_emul_usb = ADB_EMUL_USB_ANSI;
  436                 wskbd_set_evtrans(sc->sc_wskbddev, adb_to_usb_ansi, 128);
  437                 break;
  438         }
  439 #endif /* ADBKBD_EMUL_USB */
  440 
  441 #if NWSMOUSE > 0
  442         /* attach the mouse device */
  443         am.accessops = &adbkms_accessops;
  444         am.accesscookie = sc;
  445         sc->sc_wsmousedev = config_found(self, &am, wsmousedevprint,
  446             CFARGS(.iattr = "wsmousedev"));
  447 #endif
  448         adbkbd_setup_sysctl(sc);
  449 
  450         /* finally register the power button */
  451         sysmon_task_queue_init();
  452         memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch));
  453         sc->sc_sm_pbutton.smpsw_name = device_xname(sc->sc_dev);
  454         sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
  455         if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0)
  456                 aprint_error_dev(sc->sc_dev,
  457                     "unable to register power button with sysmon\n");
  458 }
  459 
  460 static void
  461 adbkbd_handler(void *cookie, int len, uint8_t *data)
  462 {
  463         struct adbkbd_softc *sc = cookie;
  464 
  465 #ifdef ADBKBD_DEBUG
  466         int i;
  467         printf("%s: %02x - ", device_xname(sc->sc_dev), sc->sc_us);
  468         for (i = 0; i < len; i++) {
  469                 printf(" %02x", data[i]);
  470         }
  471         printf("\n");
  472 #endif
  473         if (len >= 2) {
  474                 if (data[1] == sc->sc_us) {
  475                         adbkbd_keys(sc, data[2], data[3]);
  476                         return;
  477                 } else {
  478                         memcpy(sc->sc_buffer, data, len);
  479                 }
  480                 sc->sc_msg_len = len;
  481                 wakeup(&sc->sc_event);
  482         } else {
  483                 DPRINTF("bogus message\n");
  484         }
  485 }
  486 
  487 static int
  488 adbkbd_wait(struct adbkbd_softc *sc, int timeout)
  489 {
  490         int cnt = 0;
  491         
  492         if (sc->sc_poll) {
  493                 while (sc->sc_msg_len == 0) {
  494                         sc->sc_ops->poll(sc->sc_ops->cookie);
  495                 }
  496         } else {
  497                 while ((sc->sc_msg_len == 0) && (cnt < timeout)) {
  498                         tsleep(&sc->sc_event, 0, "adbkbdio", hz);
  499                         cnt++;
  500                 }
  501         }
  502         return (sc->sc_msg_len > 0);
  503 }
  504 
  505 static void
  506 adbkbd_keys(struct adbkbd_softc *sc, uint8_t k1, uint8_t k2)
  507 {
  508 
  509         /* keyboard event processing */
  510 
  511         DPRINTF("[%02x %02x]", k1, k2);
  512 
  513         if (((k1 == k2) && (k1 == 0x7f)) || (k1 == sc->sc_power)) {
  514                 uint32_t now = time_second;
  515                 uint32_t diff = now - sc->sc_timestamp;
  516 
  517                 sc->sc_timestamp = now;
  518                 if (((diff > 1) && (diff < 5)) ||
  519                      (sc->sc_power_button_delay == 0)) {
  520 #ifdef DDB
  521                         if (sc->sc_power_dbg) {
  522                                 Debugger();
  523                                 return;
  524                         }
  525 #endif
  526                         /* power button, report to sysmon */
  527                         sc->sc_pe = k1;
  528                         sysmon_task_queue_sched(0, adbkbd_powerbutton, sc);
  529                 }
  530         } else {
  531 
  532                 adbkbd_key(sc, k1);
  533                 if (k2 != 0xff)
  534                         adbkbd_key(sc, k2);
  535         }
  536 }
  537 
  538 static void
  539 adbkbd_powerbutton(void *cookie)
  540 {
  541         struct adbkbd_softc *sc = cookie;
  542 
  543         sysmon_pswitch_event(&sc->sc_sm_pbutton, 
  544             ADBK_PRESS(sc->sc_pe) ? PSWITCH_EVENT_PRESSED :
  545             PSWITCH_EVENT_RELEASED);
  546 
  547 }
  548 
  549 static inline void
  550 adbkbd_key(struct adbkbd_softc *sc, uint8_t k)
  551 {
  552 
  553         if (sc->sc_poll) {
  554                 if (sc->sc_polled_chars >= 16) {
  555                         aprint_error_dev(sc->sc_dev,"polling buffer is full\n");
  556                 }
  557                 sc->sc_pollbuf[sc->sc_polled_chars] = k;
  558                 sc->sc_polled_chars++;
  559                 return;
  560         }
  561 
  562 #if NWSMOUSE > 0
  563         /* translate some keys to mouse events */
  564         if (sc->sc_wsmousedev != NULL) {
  565                 if (ADBK_KEYVAL(k) == sc->sc_trans[1]) {
  566                         wsmouse_input(sc->sc_wsmousedev, ADBK_PRESS(k) ? 2 : 0,
  567                               0, 0, 0, 0,
  568                               WSMOUSE_INPUT_DELTA);
  569                         return;
  570                 }                       
  571                 if (ADBK_KEYVAL(k) == sc->sc_trans[2]) {
  572                         wsmouse_input(sc->sc_wsmousedev, ADBK_PRESS(k) ? 4 : 0,
  573                               0, 0, 0, 0,
  574                               WSMOUSE_INPUT_DELTA);
  575                         return;
  576                 }                       
  577         }
  578 #endif
  579 
  580 #ifdef WSDISPLAY_COMPAT_RAWKBD
  581         if (sc->sc_rawkbd) {
  582                 char cbuf[2];
  583                 int s;
  584 
  585                 cbuf[0] = k;
  586 
  587                 s = spltty();
  588                 wskbd_rawinput(sc->sc_wskbddev, cbuf, 1);
  589                 splx(s);
  590         } else {
  591 #endif
  592 
  593         if (ADBK_KEYVAL(k) == 0x39) {
  594                 /* caps lock - send up and down */
  595                 if (ADBK_PRESS(k) != sc->sc_capslock) {
  596                         sc->sc_capslock = ADBK_PRESS(k);
  597                         wskbd_input(sc->sc_wskbddev,
  598                             WSCONS_EVENT_KEY_DOWN, 0x39);
  599                         wskbd_input(sc->sc_wskbddev,
  600                             WSCONS_EVENT_KEY_UP, 0x39);
  601                 }
  602         } else {
  603                 /* normal event */
  604                 int type;
  605 
  606                 type = ADBK_PRESS(k) ? 
  607                     WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
  608                 wskbd_input(sc->sc_wskbddev, type, ADBK_KEYVAL(k));
  609         }
  610 #ifdef WSDISPLAY_COMPAT_RAWKBD
  611         }
  612 #endif
  613 }
  614 
  615 /*
  616  * Set the keyboard LED's.
  617  * 
  618  * Automatically translates from ioctl/softc format to the
  619  * actual keyboard register format
  620  */
  621 static void
  622 adbkbd_set_leds(void *cookie, int leds)
  623 {
  624         struct adbkbd_softc *sc = cookie;
  625         int aleds;
  626         short cmd;
  627         uint8_t buffer[2];
  628 
  629         DPRINTF("adbkbd_set_leds: %02x\n", leds);
  630         if ((leds & 0x07) == (sc->sc_leds & 0x07))
  631                 return;
  632 
  633         if (sc->sc_have_led_control) {
  634 
  635                 aleds = (~leds & 0x04) | 3;
  636                 if (leds & 1)
  637                         aleds &= ~2;
  638                 if (leds & 2)
  639                         aleds &= ~1;
  640 
  641                 buffer[0] = 0xff;
  642                 buffer[1] = aleds | 0xf8;
  643         
  644                 cmd = ADBLISTEN(sc->sc_adbdev->current_addr, 2);
  645                 sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 2, 
  646                     buffer);
  647         }
  648 
  649         sc->sc_leds = leds & 7;
  650 }
  651 
  652 static void 
  653 adbkbd_initleds(struct adbkbd_softc *sc)
  654 {
  655         short cmd;
  656 
  657         /* talk R2 */
  658         cmd = ADBTALK(sc->sc_adbdev->current_addr, 2);
  659         sc->sc_msg_len = 0;
  660         sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, 0, NULL);
  661         if (!adbkbd_wait(sc, 10)) {
  662                 aprint_error_dev(sc->sc_dev, "unable to read LED state\n");
  663                 return;
  664         }
  665         sc->sc_have_led_control = 1;
  666         DPRINTF("have LED control\n");  
  667         return;
  668 }
  669 
  670 static int
  671 adbkbd_enable(void *v, int on)
  672 {
  673         return 0;
  674 }
  675 
  676 static int
  677 adbkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
  678 {
  679         struct adbkbd_softc *sc = (struct adbkbd_softc *) v;
  680 
  681         switch (cmd) {
  682 
  683         case WSKBDIO_GTYPE:
  684                 if (sc->sc_emul_usb != ADB_EMUL_USB_NONE) {
  685                         *(int *)data = WSKBD_TYPE_USB;
  686                 } else {
  687                         *(int *)data = WSKBD_TYPE_ADB;
  688                 }
  689                 return 0;
  690         case WSKBDIO_SETLEDS:
  691                 adbkbd_set_leds(sc, *(int *)data);
  692                 return 0;
  693         case WSKBDIO_GETLEDS:
  694                 *(int *)data = sc->sc_leds;
  695                 return 0;
  696 #ifdef WSDISPLAY_COMPAT_RAWKBD
  697         case WSKBDIO_SETMODE:
  698                 sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
  699                 return 0;
  700 #endif
  701         }
  702 
  703         return EPASSTHROUGH;
  704 }
  705 
  706 int
  707 adbkbd_cnattach(void)
  708 {
  709 
  710         adbkbd_is_console = 1;
  711         return 0;
  712 }
  713 
  714 static void
  715 adbkbd_cngetc(void *v, u_int *type, int *data)
  716 {
  717         struct adbkbd_softc *sc = v;
  718         int key, press, val;
  719         int s;
  720 
  721         s = splhigh();
  722 
  723         KASSERT(sc->sc_poll);
  724 
  725         DPRINTF("polling...");
  726         while (sc->sc_polled_chars == 0) {
  727                 sc->sc_ops->poll(sc->sc_ops->cookie);
  728         }
  729         DPRINTF(" got one\n");
  730         splx(s);
  731 
  732         key = sc->sc_pollbuf[0];
  733         sc->sc_polled_chars--;
  734         memmove(sc->sc_pollbuf, sc->sc_pollbuf + 1,
  735                 sc->sc_polled_chars);
  736 
  737         press = ADBK_PRESS(key);
  738         val = ADBK_KEYVAL(key);
  739 
  740         *data = val;
  741         *type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
  742 }
  743 
  744 static void
  745 adbkbd_cnpollc(void *v, int on)
  746 {
  747         struct adbkbd_softc *sc = v;
  748 
  749         sc->sc_poll = on;
  750         if (!on) {
  751                 int i;
  752 
  753                 /* feed the poll buffer's content to wskbd */
  754                 for (i = 0; i < sc->sc_polled_chars; i++) {
  755                         adbkbd_key(sc, sc->sc_pollbuf[i]);
  756                 }
  757                 sc->sc_polled_chars = 0;
  758         }
  759 }
  760 
  761 #if NWSMOUSE > 0
  762 /* stuff for the pseudo mouse */
  763 static int
  764 adbkms_enable(void *v)
  765 {
  766         return 0;
  767 }
  768 
  769 static int
  770 adbkms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
  771 {
  772 
  773         switch (cmd) {
  774         case WSMOUSEIO_GTYPE:
  775                 *(u_int *)data = WSMOUSE_TYPE_PSEUDO;
  776                 break;
  777 
  778         default:
  779                 return (EPASSTHROUGH);
  780         }
  781         return (0);
  782 }
  783 
  784 static void
  785 adbkms_disable(void *v)
  786 {
  787 }
  788 
  789 static int
  790 adbkbd_sysctl_mid(SYSCTLFN_ARGS)
  791 {
  792         struct sysctlnode node = *rnode;
  793         struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data;
  794         const int *np = newp;
  795         int reg;
  796 
  797         DPRINTF("adbkbd_sysctl_mid\n");
  798         reg = sc->sc_trans[1];
  799         if (np) {
  800                 /* we're asked to write */      
  801                 node.sysctl_data = &reg;
  802                 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
  803                         
  804                         sc->sc_trans[1] = *(int *)node.sysctl_data;
  805                         return 0;
  806                 }
  807                 return EINVAL;
  808         } else {
  809                 node.sysctl_data = &reg;
  810                 node.sysctl_size = 4;
  811                 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
  812         }
  813 }
  814 
  815 static int
  816 adbkbd_sysctl_right(SYSCTLFN_ARGS)
  817 {
  818         struct sysctlnode node = *rnode;
  819         struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data;
  820         const int *np = newp;
  821         int reg;
  822 
  823         DPRINTF("adbkbd_sysctl_right\n");
  824         reg = sc->sc_trans[2];
  825         if (np) {
  826                 /* we're asked to write */      
  827                 node.sysctl_data = &reg;
  828                 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
  829                         
  830                         sc->sc_trans[2] = *(int *)node.sysctl_data;
  831                         return 0;
  832                 }
  833                 return EINVAL;
  834         } else {
  835                 node.sysctl_data = &reg;
  836                 node.sysctl_size = 4;
  837                 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
  838         }
  839 }
  840 
  841 #endif /* NWSMOUSE > 0 */
  842 
  843 static int
  844 adbkbd_sysctl_usb(SYSCTLFN_ARGS)
  845 {
  846         struct sysctlnode node = *rnode;
  847         struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data;
  848         const int *np = newp;
  849         int reg;
  850 
  851         DPRINTF("%s\n", __func__);
  852         reg = sc->sc_emul_usb;
  853         if (np) {
  854                 /* we're asked to write */      
  855                 node.sysctl_data = &reg;
  856                 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
  857                         
  858                         sc->sc_emul_usb = *(int *)node.sysctl_data;
  859                         switch (sc->sc_emul_usb) {
  860                         case ADB_EMUL_USB_NONE:
  861                                 wskbd_set_evtrans(sc->sc_wskbddev, NULL, 0);
  862                                 break;
  863                         case ADB_EMUL_USB_ANSI:
  864                                 wskbd_set_evtrans(sc->sc_wskbddev,
  865                                     adb_to_usb_ansi, 128);
  866                                 break;
  867                         case ADB_EMUL_USB_ISO:
  868                                 wskbd_set_evtrans(sc->sc_wskbddev,
  869                                     adb_to_usb_iso, 128);
  870                                 break;
  871                         case ADB_EMUL_USB_JIS:
  872                                 wskbd_set_evtrans(sc->sc_wskbddev,
  873                                     adb_to_usb_jis, 128);
  874                                 break;
  875                         default:
  876                                 return EINVAL;
  877                                 break;
  878                         }
  879                         return 0;
  880                 }
  881                 return EINVAL;
  882         } else {
  883                 node.sysctl_data = &reg;
  884                 node.sysctl_size = sizeof(reg);
  885                 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
  886         }
  887 }
  888 
  889 static int
  890 adbkbd_sysctl_dbg(SYSCTLFN_ARGS)
  891 {
  892         struct sysctlnode node = *rnode;
  893         struct adbkbd_softc *sc=(struct adbkbd_softc *)node.sysctl_data;
  894         const int *np = newp;
  895         bool reg;
  896 
  897         DPRINTF("%s\n", __func__);
  898         reg = sc->sc_power_dbg;
  899         if (np) {
  900                 /* we're asked to write */      
  901                 node.sysctl_data = &reg;
  902                 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
  903                         
  904                         sc->sc_power_dbg = *(bool *)node.sysctl_data;
  905                         return 0;
  906                 }
  907                 return EINVAL;
  908         } else {
  909                 node.sysctl_data = &reg;
  910                 node.sysctl_size = sizeof(reg);
  911                 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
  912         }
  913 }
  914 
  915 static void
  916 adbkbd_setup_sysctl(struct adbkbd_softc *sc)
  917 {
  918         const struct sysctlnode *me, *node;
  919         int ret;
  920 
  921         DPRINTF("%s: sysctl setup\n", device_xname(sc->sc_dev));
  922         ret = sysctl_createv(NULL, 0, NULL, &me,
  923                CTLFLAG_READWRITE,
  924                CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
  925                NULL, 0, NULL, 0,
  926                CTL_MACHDEP, CTL_CREATE, CTL_EOL);
  927         ret = sysctl_createv(NULL, 0, NULL,
  928             (void *)&node, 
  929             CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
  930             CTLTYPE_INT, "emulate_usb", "USB keyboard emulation", 
  931             adbkbd_sysctl_usb, 1, (void *)sc, 0, CTL_MACHDEP, 
  932             me->sysctl_num, CTL_CREATE, CTL_EOL);
  933         ret = sysctl_createv(NULL, 0, NULL,
  934             (void *)&node, 
  935             CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
  936             CTLTYPE_BOOL, "power_ddb", "power button triggers ddb", 
  937             adbkbd_sysctl_dbg, 1, (void *)sc, 0, CTL_MACHDEP, 
  938             me->sysctl_num, CTL_CREATE, CTL_EOL);
  939 #if NWSMOUSE > 0
  940         if (sc->sc_wsmousedev != NULL) {
  941                 ret = sysctl_createv(NULL, 0, NULL,
  942                     (void *)&node, 
  943                     CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
  944                     CTLTYPE_INT, "middle", "middle mouse button", 
  945                     adbkbd_sysctl_mid, 1, (void *)sc, 0, CTL_MACHDEP, 
  946                     me->sysctl_num, CTL_CREATE, CTL_EOL);
  947 
  948                 ret = sysctl_createv(NULL, 0, NULL, 
  949                     (void *)&node, 
  950                     CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
  951                     CTLTYPE_INT, "right", "right mouse button", 
  952                     adbkbd_sysctl_right, 2, (void *)sc, 0, CTL_MACHDEP, 
  953                     me->sysctl_num, CTL_CREATE, CTL_EOL);
  954         }
  955 #endif /* NWSMOUSE > 0 */
  956 
  957         (void)ret;
  958 }
  959 
  960 SYSCTL_SETUP(sysctl_adbkbdtrans_setup, "adbkbd translator setup")
  961 {
  962 
  963         sysctl_createv(NULL, 0, NULL, NULL,
  964                        CTLFLAG_PERMANENT,
  965                        CTLTYPE_NODE, "machdep", NULL,
  966                        NULL, 0, NULL, 0,
  967                        CTL_MACHDEP, CTL_EOL);
  968 }

Cache object: 79bba1f99ce4fb3af0219835f0d482bb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.