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/akbd.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 /*      $OpenBSD: akbd.c,v 1.16 2022/10/21 22:42:36 gkoehler Exp $      */
    2 /*      $NetBSD: akbd.c,v 1.17 2005/01/15 16:00:59 chs Exp $    */
    3 
    4 /*
    5  * Copyright (C) 1998   Colin Wood
    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/param.h>
   35 #include <sys/timeout.h>
   36 #include <sys/kernel.h>
   37 #include <sys/device.h>
   38 #include <sys/systm.h>
   39 
   40 #include <dev/wscons/wsconsio.h>
   41 #include <dev/wscons/wskbdvar.h>
   42 #include <dev/wscons/wsksymdef.h>
   43 #include <dev/wscons/wsksymvar.h>
   44 
   45 #include <machine/autoconf.h>
   46 #include <machine/cpu.h>
   47 
   48 #include <dev/adb/adb.h>
   49 #include <dev/adb/akbdmap.h>
   50 #include <dev/adb/akbdvar.h>
   51 #include <dev/adb/keyboard.h>
   52 
   53 /*
   54  * Function declarations.
   55  */
   56 int     akbdmatch(struct device *, void *, void *);
   57 void    akbdattach(struct device *, struct device *, void *);
   58 
   59 /* Driver definition. */
   60 const struct cfattach akbd_ca = {
   61         sizeof(struct akbd_softc), akbdmatch, akbdattach
   62 };
   63 struct cfdriver akbd_cd = {
   64         NULL, "akbd", DV_DULL
   65 };
   66 
   67 int     akbd_enable(void *, int);
   68 void    akbd_set_leds(void *, int);
   69 int     akbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
   70 
   71 
   72 struct wskbd_accessops akbd_accessops = {
   73         akbd_enable,
   74         akbd_set_leds,
   75         akbd_ioctl,
   76 };
   77 
   78 struct wskbd_mapdata akbd_keymapdata = {
   79         akbd_keydesctab,
   80 #ifdef AKBD_LAYOUT
   81         AKBD_LAYOUT,
   82 #else
   83         KB_US | KB_DEFAULT,
   84 #endif
   85 };
   86 
   87 void    akbd_adbcomplete(caddr_t, caddr_t, int);
   88 void    akbd_capslockwrapper(struct akbd_softc *, int);
   89 void    akbd_input(struct akbd_softc *, int);
   90 void    akbd_processevent(struct akbd_softc *, adb_event_t *);
   91 #ifdef notyet
   92 u_char  getleds(int);
   93 int     setleds(struct akbd_softc *, u_char);
   94 void    blinkleds(struct akbd_softc *);
   95 #endif
   96 
   97 int
   98 akbdmatch(struct device *parent, void *vcf, void *aux)
   99 {
  100         struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
  101 
  102         if (strcmp(aa_args->name, adb_device_name) != 0)
  103                 return (0);
  104 
  105         if (aa_args->origaddr == ADBADDR_KBD)
  106                 return (1);
  107         else
  108                 return (0);
  109 }
  110 
  111 void
  112 akbdattach(struct device *parent, struct device *self, void *aux)
  113 {
  114         ADBSetInfoBlock adbinfo;
  115         struct akbd_softc *sc = (struct akbd_softc *)self;
  116         struct adb_attach_args *aa_args = (struct adb_attach_args *)aux;
  117         int error, kbd_done;
  118         short cmd;
  119         u_char buffer[9];
  120         struct wskbddev_attach_args a;
  121         static int akbd_console_initted;
  122         int wskbd_eligible = 1;
  123 
  124         sc->origaddr = aa_args->origaddr;
  125         sc->adbaddr = aa_args->adbaddr;
  126         sc->handler_id = aa_args->handler_id;
  127 
  128         sc->sc_leds = (u_int8_t)0x00;   /* initially off */
  129         sc->sc_caps = 0;
  130         sc->sc_iso = 0;
  131 
  132         adbinfo.siServiceRtPtr = (Ptr)akbd_adbcomplete;
  133         adbinfo.siDataAreaAddr = (caddr_t)sc;
  134 
  135         printf(": ");
  136         switch (sc->handler_id) {
  137         case ADB_STDKBD:
  138                 printf("standard keyboard\n");
  139                 break;
  140         case ADB_ISOKBD:
  141                 printf("standard keyboard (ISO layout)\n");
  142                 sc->sc_iso = 1;
  143                 break;
  144         case ADB_EXTKBD:
  145                 cmd = ADBTALK(sc->adbaddr, 1);
  146                 kbd_done =
  147                     (adb_op_sync((Ptr)buffer, cmd) == 0);
  148 
  149                 /* Ignore Logitech MouseMan/Trackman pseudo keyboard */
  150                 if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x20) {
  151                         printf("Mouseman (non-EMP) pseudo keyboard\n");
  152                         adbinfo.siServiceRtPtr = (Ptr)0;
  153                         adbinfo.siDataAreaAddr = (Ptr)0;
  154                         wskbd_eligible = 0;
  155                 } else if (kbd_done && buffer[1] == 0x9a && buffer[2] == 0x21) {
  156                         printf("Trackman (non-EMP) pseudo keyboard\n");
  157                         adbinfo.siServiceRtPtr = (Ptr)0;
  158                         adbinfo.siDataAreaAddr = (Ptr)0;
  159                         wskbd_eligible = 0;
  160                 } else {
  161                         printf("extended keyboard\n");
  162 #ifdef notyet
  163                         blinkleds(sc);
  164 #endif
  165                 }
  166                 break;
  167         case ADB_EXTISOKBD:
  168                 printf("extended keyboard (ISO layout)\n");
  169                 sc->sc_iso = 1;
  170 #ifdef notyet
  171                 blinkleds(sc);
  172 #endif
  173                 break;
  174         case ADB_KBDII:
  175                 printf("keyboard II\n");
  176                 break;
  177         case ADB_ISOKBDII:
  178                 printf("keyboard II (ISO layout)\n");
  179                 sc->sc_iso = 1;
  180                 break;
  181         case ADB_PBKBD:
  182                 printf("PowerBook keyboard\n");
  183                 break;
  184         case ADB_PBISOKBD:
  185                 printf("PowerBook keyboard (ISO layout)\n");
  186                 sc->sc_iso = 1;
  187                 break;
  188         case ADB_ADJKPD:
  189                 printf("adjustable keypad\n");
  190                 wskbd_eligible = 0;
  191                 break;
  192         case ADB_ADJKBD:
  193                 printf("adjustable keyboard\n");
  194                 break;
  195         case ADB_ADJISOKBD:
  196                 printf("adjustable keyboard (ISO layout)\n");
  197                 sc->sc_iso = 1;
  198                 break;
  199         case ADB_ADJJAPKBD:
  200                 printf("adjustable keyboard (Japanese layout)\n");
  201                 break;
  202         case ADB_PBEXTISOKBD:
  203                 printf("PowerBook extended keyboard (ISO layout)\n");
  204                 sc->sc_iso = 1;
  205                 break;
  206         case ADB_PBEXTJAPKBD:
  207                 printf("PowerBook extended keyboard (Japanese layout)\n");
  208                 break;
  209         case ADB_JPKBDII:
  210                 printf("keyboard II (Japanese layout)\n");
  211                 break;
  212         case ADB_PBEXTKBD:
  213                 printf("PowerBook extended keyboard\n");
  214                 break;
  215         case ADB_DESIGNKBD:
  216                 printf("extended keyboard\n");
  217 #ifdef notyet
  218                 blinkleds(sc);
  219 #endif
  220                 break;
  221         case ADB_PBJPKBD:
  222                 printf("PowerBook keyboard (Japanese layout)\n");
  223                 break;
  224         case ADB_PBG3JPKBD:
  225                 printf("PowerBook G3 keyboard (Japanese layout)\n");
  226                 break;
  227         case ADB_PBG4KBD:
  228                 printf("PowerBook G4 keyboard (Inverted T)\n");
  229                 break;
  230         case ADB_IBITISOKBD:
  231                 printf("iBook keyboard with inverted T (ISO layout)\n");
  232                 sc->sc_iso = 1;
  233                 break;
  234         default:
  235                 printf("mapped device (%d)\n", sc->handler_id);
  236 #if 0
  237                 wskbd_eligible = 0;
  238 #endif
  239                 break;
  240         }
  241         error = set_adb_info(&adbinfo, sc->adbaddr);
  242 #ifdef ADB_DEBUG
  243         if (adb_debug)
  244                 printf("akbd: returned %d from set_adb_info\n", error);
  245 #endif
  246 
  247         if (akbd_is_console() && wskbd_eligible)
  248                 a.console = (++akbd_console_initted == 1);
  249         else
  250                 a.console = 0;
  251         a.keymap = &akbd_keymapdata;
  252         a.accessops = &akbd_accessops;
  253         a.accesscookie = sc;
  254 
  255         sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
  256 }
  257 
  258 
  259 /*
  260  * Handle putting the keyboard data received from the ADB into
  261  * an ADB event record.
  262  */
  263 void
  264 akbd_adbcomplete(caddr_t buffer, caddr_t data_area, int adb_command)
  265 {
  266         adb_event_t event;
  267         struct akbd_softc *sc;
  268         int adbaddr;
  269 #ifdef ADB_DEBUG
  270         int i;
  271 
  272         if (adb_debug)
  273                 printf("adb: transaction completion\n");
  274 #endif
  275 
  276         adbaddr = ADB_CMDADDR(adb_command);
  277         sc = (struct akbd_softc *)data_area;
  278 
  279         event.byte_count = buffer[0];
  280         memcpy(event.bytes, buffer + 1, event.byte_count);
  281 
  282 #ifdef ADB_DEBUG
  283         if (adb_debug) {
  284                 printf("akbd: from %d at %d (org %d) %d:", adbaddr,
  285                     sc->handler_id, sc->origaddr, buffer[0]);
  286                 for (i = 1; i <= buffer[0]; i++)
  287                         printf(" %x", buffer[i]);
  288                 printf("\n");
  289         }
  290 #endif
  291 
  292         if (sc->sc_wskbddev != NULL)
  293                 akbd_processevent(sc, &event);
  294 }
  295 
  296 #ifdef notyet
  297 /*
  298  * Get the actual hardware LED state and convert it to softc format.
  299  */
  300 u_char
  301 getleds(int addr)
  302 {
  303         short cmd;
  304         u_char buffer[9], leds;
  305 
  306         leds = 0x00;    /* all off */
  307         buffer[0] = 0;
  308 
  309         cmd = ADBTALK(addr, 2);
  310         if (adb_op_sync((Ptr)buffer, cmd) == 0 &&
  311             buffer[0] > 0)
  312                 leds = ~(buffer[2]) & 0x07;
  313 
  314         return (leds);
  315 }
  316 
  317 /*
  318  * Set the keyboard LED's.
  319  *
  320  * Automatically translates from ioctl/softc format to the
  321  * actual keyboard register format
  322  */
  323 int
  324 setleds(struct akbd_softc *sc, u_char leds)
  325 {
  326         int addr;
  327         short cmd;
  328         u_char buffer[9];
  329 
  330         addr = sc->adbaddr;
  331         buffer[0] = 0;
  332 
  333         cmd = ADBTALK(addr, 2);
  334         if (adb_op_sync((Ptr)buffer, cmd) || buffer[0] == 0)
  335                 return (EIO);
  336 
  337         leds = ~leds & 0x07;
  338         buffer[2] &= 0xf8;
  339         buffer[2] |= leds;
  340 
  341         cmd = ADBLISTEN(addr, 2);
  342         adb_op_sync((Ptr)buffer, cmd);
  343 
  344         /* talk R2 */
  345         cmd = ADBTALK(addr, 2);
  346         if (adb_op_sync((Ptr)buffer, cmd) || buffer[0] == 0)
  347                 return (EIO);
  348 
  349         if ((buffer[2] & 0xf8) != leds)
  350                 return (EIO);
  351         else
  352                 return (0);
  353 }
  354 
  355 /*
  356  * Toggle all of the LED's on and off, just for show.
  357  */
  358 void
  359 blinkleds(struct akbd_softc *sc)
  360 {
  361         u_char origleds;
  362 
  363         origleds = getleds(sc->adbaddr);
  364         setleds(sc, LED_NUMLOCK | LED_CAPSLOCK | LED_SCROLL_LOCK);
  365         delay(400000);
  366         setleds(sc, origleds);
  367 
  368         if (origleds & LED_NUMLOCK)
  369                 sc->sc_leds |= WSKBD_LED_NUM;
  370         if (origleds & LED_CAPSLOCK)
  371                 sc->sc_leds |= WSKBD_LED_CAPS;
  372         if (origleds & LED_SCROLL_LOCK)
  373                 sc->sc_leds |= WSKBD_LED_SCROLL;
  374 }
  375 #endif
  376 
  377 int
  378 akbd_enable(void *v, int on)
  379 {
  380         return 0;
  381 }
  382 
  383 void
  384 akbd_set_leds(void *v, int on)
  385 {
  386 #ifdef notyet
  387         struct akbd_softc *sc = v;
  388         int leds;
  389 
  390         if (sc->sc_extended) {
  391                 if (sc->sc_leds == on)
  392                         return;
  393 
  394                 leds = 0;
  395                 if (on & WSKBD_LED_NUM)
  396                         leds |= LED_NUMLOCK;
  397                 if (on & WSKBD_LED_CAPS)
  398                         leds |= LED_CAPSLOCK;
  399                 if (on & WSKBD_LED_SCROLL)
  400                         leds |= LED_SCROLL_LOCK;
  401 
  402                 setleds(sc, leds);
  403         }
  404 #endif
  405 }
  406 
  407 int
  408 akbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
  409 {
  410         struct akbd_softc *sc = v;
  411 
  412         switch (cmd) {
  413 
  414         case WSKBDIO_GTYPE:
  415                 *(int *)data = WSKBD_TYPE_ADB;
  416                 return 0;
  417         case WSKBDIO_SETLEDS:
  418                 akbd_set_leds(v, *(int *)data);
  419                 return 0;
  420         case WSKBDIO_GETLEDS:
  421                 *(int *)data = sc->sc_leds;
  422                 return 0;
  423 #ifdef WSDISPLAY_COMPAT_RAWKBD
  424         case WSKBDIO_SETMODE:
  425                 sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
  426                 return (0);
  427 #endif
  428         default:
  429                 return (-1);
  430         }
  431 }
  432 
  433 /*
  434  * The ``caps lock'' key is special: since on earlier keyboards, the physical
  435  * key stays down when pressed, we will get a notification of the key press,
  436  * but not of the key release. Then, when it is pressed again, we will not get
  437  * a notification of the key press, but will see the key release.
  438  *
  439  * This is not exactly true. We see the missing release and press events both
  440  * as the release of the power (reset) key.
  441  *
  442  * To avoid confusing them with real power key presses, we maintain two
  443  * states for the caps lock key: logically down (from wscons' point of view),
  444  * and ``physically'' down (from the adb messages point of view), to ignore
  445  * the power key. But since one may press the power key while the caps lock
  446  * is held down, we also have to remember the state of the power key... this
  447  * is quite messy.
  448  */
  449 
  450 /*
  451  * Values for caps lock state machine
  452  */
  453 #define CL_DOWN_ADB     0x01
  454 #define CL_DOWN_LOGICAL 0x02
  455 #define CL_DOWN_RESET   0x04
  456 
  457 /*
  458  * Given a keyboard ADB event, decode the keycodes and pass them to wskbd.
  459  */
  460 void
  461 akbd_processevent(struct akbd_softc *sc, adb_event_t *event)
  462 {
  463         switch (event->byte_count) {
  464         case 1:
  465                 akbd_capslockwrapper(sc, event->bytes[0]);
  466                 break;
  467         case 2:
  468                 /*
  469                  * The reset (or power) key sends 0x7f7f on press and
  470                  * 0xffff on release.
  471                  */
  472                 if (event->bytes[0] == event->bytes[1] &&
  473                     ADBK_KEYVAL(event->bytes[0]) == ADBK_RESET) {
  474                         if (event->bytes[0] == ADBK_KEYDOWN(ADBK_RESET)) {
  475                                 SET(sc->sc_caps, CL_DOWN_RESET);
  476                                 adb_power_button_intr();
  477                         } else {
  478                                 if (ISSET(sc->sc_caps, CL_DOWN_RESET))
  479                                         CLR(sc->sc_caps, CL_DOWN_RESET);
  480                                 else if (ISSET(sc->sc_caps, CL_DOWN_ADB)) {
  481                                         akbd_input(sc, ISSET(sc->sc_caps,
  482                                             CL_DOWN_LOGICAL) ?
  483                                               ADBK_KEYDOWN(ADBK_CAPSLOCK) :
  484                                               ADBK_KEYUP(ADBK_CAPSLOCK));
  485                                         sc->sc_caps ^= CL_DOWN_LOGICAL;
  486                                 }
  487                         }
  488                 } else {
  489                         akbd_capslockwrapper(sc, event->bytes[0]);
  490                         akbd_capslockwrapper(sc, event->bytes[1]);
  491                 }
  492                 break;
  493         default:
  494 #ifdef DIAGNOSTIC
  495                 printf("%s: unexpected message length %d\n",
  496                     sc->sc_dev.dv_xname, event->byte_count);
  497 #endif
  498                 break;
  499         }
  500 
  501 }
  502 
  503 void
  504 akbd_capslockwrapper(struct akbd_softc *sc, int key)
  505 {
  506         if (ADBK_KEYVAL(key) == ADBK_CAPSLOCK)
  507                 sc->sc_caps ^= CL_DOWN_ADB;
  508 
  509         if (key != 0xff)
  510                 akbd_input(sc, key);
  511 }
  512 
  513 static inline int
  514 akbd_iso_swap(int keycode)
  515 {
  516         switch (keycode) {
  517         case 10:
  518                 return (50);
  519         case 50:
  520                 return (10);
  521         default:
  522                 return (keycode);
  523         }
  524 }
  525 
  526 int adb_polledkey;
  527 void
  528 akbd_input(struct akbd_softc *sc, int key)
  529 {
  530         int press, val;
  531         int type;
  532 
  533         press = ADBK_PRESS(key);
  534         val = ADBK_KEYVAL(key);
  535 
  536         if (sc->sc_iso)
  537                 val = akbd_iso_swap(val);
  538 
  539         type = press ? WSCONS_EVENT_KEY_DOWN : WSCONS_EVENT_KEY_UP;
  540 
  541         if (adb_polling) {
  542                 adb_polledkey = key;
  543 #ifdef WSDISPLAY_COMPAT_RAWKBD
  544         } else if (sc->sc_rawkbd) {
  545                 char cbuf[2];
  546                 int c, j, s;
  547 
  548                 j = 0;
  549 
  550                 c = keyboard[val];
  551                 if (c == 0) {
  552                         return; /* XXX */
  553                 }
  554                 if (c & 0x80)
  555                         cbuf[j++] = 0xe0;
  556                 cbuf[j] = c & 0x7f;
  557                 if (type == WSCONS_EVENT_KEY_UP)
  558                         cbuf[j] |= 0x80;
  559                 j++;
  560                 s = spltty();
  561                 wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
  562                 splx(s);
  563 #endif
  564         } else {
  565                 wskbd_input(sc->sc_wskbddev, type, val);
  566         }
  567 }

Cache object: 3258bb69fbbddb8381804089ad7f2c8d


[ 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.