root/dev/adb/akbd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. akbdmatch
  2. akbdattach
  3. akbd_adbcomplete
  4. getleds
  5. setleds
  6. blinkleds
  7. akbd_enable
  8. akbd_set_leds
  9. akbd_ioctl
  10. akbd_rawrepeat
  11. akbd_processevent
  12. akbd_capslockwrapper
  13. akbd_input

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

/* [<][>][^][v][top][bottom][index][help] */