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_ms.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_ms.c,v 1.21 2021/08/07 16:19:09 thorpej 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_ms.c,v 1.21 2021/08/07 16:19:09 thorpej 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/signalvar.h>
   44 #include <sys/systm.h>
   45 #include <sys/kernel.h>
   46 #include <sys/sysctl.h>
   47 
   48 #include <machine/autoconf.h>
   49 
   50 #include <dev/wscons/wsconsio.h>
   51 #include <dev/wscons/wsmousevar.h>
   52 
   53 #include <machine/adbsys.h>
   54 #include <dev/adb/adbvar.h>
   55 
   56 #include "adbdebug.h"
   57 
   58 #ifdef ADBMS_DEBUG
   59 #define DPRINTF printf
   60 #else
   61 #define DPRINTF while (0) printf
   62 #endif
   63 
   64 /*
   65  * State info, per mouse instance.
   66  */
   67 struct adbms_softc {
   68         device_t        sc_dev;
   69         struct adb_device *sc_adbdev;
   70         struct adb_bus_accessops *sc_ops;
   71 
   72         /* Extended Mouse Protocol info, faked for non-EMP mice */
   73         u_int8_t        sc_class;       /* mouse class (mouse, trackball) */
   74         u_int8_t        sc_buttons;     /* number of buttons */
   75         u_int32_t       sc_res;         /* mouse resolution (dpi) */
   76         char            sc_devid[5];    /* device indentifier */
   77         uint8_t         sc_us;          /* cmd to watch for */
   78         int             sc_mb;          /* current button state */
   79         device_t        sc_wsmousedev;
   80         /* helpers for trackpads */
   81         int             sc_down;
   82         /*
   83          * trackpad protocol variant. Known so far:
   84          * 2 buttons - PowerBook 3400, single events on button 3 and 4 indicate
   85          *             finger down and up
   86          * 4 buttons - iBook G4, button 6 indicates finger down, button 4 is
   87          *             always down
   88          */
   89         int             sc_x, sc_y;
   90         int             sc_tapping;
   91         /* buffers */
   92         int             sc_poll;
   93         int             sc_msg_len;
   94         int             sc_event;
   95         uint8_t         sc_buffer[16];
   96 };
   97 
   98 /* EMP device classes */
   99 #define MSCLASS_TABLET          0
  100 #define MSCLASS_MOUSE           1
  101 #define MSCLASS_TRACKBALL       2
  102 #define MSCLASS_TRACKPAD        3
  103 
  104 /*
  105  * Function declarations.
  106  */
  107 static int      adbms_match(device_t, cfdata_t, void *);
  108 static void     adbms_attach(device_t, device_t, void *);
  109 static void     ems_init(struct adbms_softc *);
  110 static void     init_trackpad(struct adbms_softc *);
  111 static void     adbms_init_mouse(struct adbms_softc *);
  112 static void     adbms_init_turbo(struct adbms_softc *);
  113 static void     adbms_init_uspeed(struct adbms_softc *);
  114 static void     adbms_process_event(struct adbms_softc *, int, uint8_t *);
  115 static int      adbms_send_sync(struct adbms_softc *, uint8_t, int, uint8_t *);
  116 
  117 /* Driver definition. */
  118 CFATTACH_DECL_NEW(adbms, sizeof(struct adbms_softc),
  119     adbms_match, adbms_attach, NULL, NULL);
  120 
  121 static int adbms_enable(void *);
  122 static int adbms_ioctl(void *, u_long, void *, int, struct lwp *);
  123 static void adbms_disable(void *);
  124 
  125 /*
  126  * handle tapping the trackpad
  127  * different pads report different button counts and use slightly different
  128  * protocols
  129  */
  130 static void adbms_mangle_2(struct adbms_softc *, int);
  131 static void adbms_mangle_4(struct adbms_softc *, int);
  132 static void adbms_handler(void *, int, uint8_t *);
  133 static int  adbms_wait(struct adbms_softc *, int);
  134 static int  sysctl_adbms_tap(SYSCTLFN_ARGS);
  135 
  136 const struct wsmouse_accessops adbms_accessops = {
  137         adbms_enable,
  138         adbms_ioctl,
  139         adbms_disable,
  140 };
  141 
  142 static int
  143 adbms_match(device_t parent, cfdata_t cf, void *aux)
  144 {
  145         struct adb_attach_args *aaa = aux;
  146 
  147         if (aaa->dev->original_addr == ADBADDR_MS)
  148                 return 1;
  149         else
  150                 return 0;
  151 }
  152 
  153 static void
  154 adbms_attach(device_t parent, device_t self, void *aux)
  155 {
  156         struct adbms_softc *sc = device_private(self);
  157         struct adb_attach_args *aaa = aux;
  158         struct wsmousedev_attach_args a;
  159 
  160         sc->sc_dev = self;
  161         sc->sc_ops = aaa->ops;
  162         sc->sc_adbdev = aaa->dev;
  163         sc->sc_adbdev->cookie = sc;
  164         sc->sc_adbdev->handler = adbms_handler;
  165         sc->sc_us = ADBTALK(sc->sc_adbdev->current_addr, 0);
  166         printf(" addr %d: ", sc->sc_adbdev->current_addr);
  167 
  168         sc->sc_class = MSCLASS_MOUSE;
  169         sc->sc_buttons = 1;
  170         sc->sc_res = 100;
  171         sc->sc_devid[0] = 0;
  172         sc->sc_devid[4] = 0;
  173         sc->sc_poll = 0;
  174         sc->sc_msg_len = 0;
  175         sc->sc_tapping = 1;
  176 
  177         ems_init(sc);
  178 
  179         /* print out the type of mouse we have */
  180         switch (sc->sc_adbdev->handler_id) {
  181         case ADBMS_100DPI:
  182                 printf("%d-button, %u dpi mouse\n", sc->sc_buttons,
  183                     sc->sc_res);
  184                 break;
  185         case ADBMS_200DPI:
  186                 sc->sc_res = 200;
  187                 printf("%d-button, %u dpi mouse\n", sc->sc_buttons,
  188                     sc->sc_res);
  189                 break;
  190         case ADBMS_MSA3:
  191                 printf("Mouse Systems A3 mouse, %d-button, %u dpi\n",
  192                     sc->sc_buttons, sc->sc_res);
  193                 break;
  194         case ADBMS_USPEED:
  195                 printf("MicroSpeed mouse, default parameters\n");
  196                 break;
  197         case ADBMS_UCONTOUR:
  198                 printf("Contour mouse, default parameters\n");
  199                 break;
  200         case ADBMS_TURBO:
  201                 printf("Kensington Turbo Mouse\n");
  202                 break;
  203         case ADBMS_EXTENDED:
  204                 if (sc->sc_devid[0] == '\0') {
  205                         printf("Logitech ");
  206                         switch (sc->sc_class) {
  207                         case MSCLASS_MOUSE:
  208                                 printf("MouseMan (non-EMP) mouse");
  209                                 break;
  210                         case MSCLASS_TRACKBALL:
  211                                 printf("TrackMan (non-EMP) trackball");
  212                                 break;
  213                         default:
  214                                 printf("non-EMP relative positioning device");
  215                                 break;
  216                         }
  217                         printf("\n");
  218                 } else {
  219                         printf("EMP ");
  220                         switch (sc->sc_class) {
  221                         case MSCLASS_TABLET:
  222                                 printf("tablet");
  223                                 break;
  224                         case MSCLASS_MOUSE:
  225                                 printf("mouse");
  226                                 break;
  227                         case MSCLASS_TRACKBALL:
  228                                 printf("trackball");
  229                                 break;
  230                         case MSCLASS_TRACKPAD:
  231                                 printf("trackpad");
  232                                 init_trackpad(sc);
  233                                 break;
  234                         default:
  235                                 printf("unknown device");
  236                                 break;
  237                         }
  238                         printf(" <%s> %d-button, %u dpi\n", sc->sc_devid,
  239                             sc->sc_buttons, sc->sc_res);
  240                 }
  241                 break;
  242         default:
  243                 printf("relative positioning device (mouse?) (%d)\n",
  244                         sc->sc_adbdev->handler_id);
  245                 break;
  246         }
  247 
  248         a.accessops = &adbms_accessops;
  249         a.accesscookie = sc;
  250         sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint, CFARGS_NONE);
  251 }
  252 
  253 
  254 /*
  255  * Initialize extended mouse support -- probes devices as described
  256  * in Inside Macintosh: Devices, Chapter 5 "ADB Manager".
  257  *
  258  * Extended Mouse Protocol is documented in TechNote HW1:
  259  *      "ADB - The Untold Story:  Space Aliens Ate My Mouse"
  260  *
  261  * Supports: Extended Mouse Protocol, MicroSpeed Mouse Deluxe,
  262  *           Mouse Systems A^3 Mouse, Logitech non-EMP MouseMan
  263  */
  264 void
  265 ems_init(struct adbms_softc *sc)
  266 {
  267         
  268         DPRINTF("ems_init %d\n", sc->sc_adbdev->handler_id);
  269 
  270         switch (sc->sc_adbdev->handler_id) {
  271                 case ADBMS_USPEED:
  272                 case ADBMS_UCONTOUR:
  273                         adbms_init_uspeed(sc);
  274                         return;
  275                 case ADBMS_TURBO:
  276                         adbms_init_turbo(sc);
  277                         return;
  278                 case ADBMS_100DPI:
  279                 case ADBMS_200DPI:
  280                         adbms_init_mouse(sc);
  281         }
  282 }
  283 
  284 static void
  285 adbms_init_uspeed(struct adbms_softc *sc)
  286 {
  287         uint8_t cmd, addr, buffer[4];
  288 
  289         addr = sc->sc_adbdev->current_addr;
  290 
  291         /* Found MicroSpeed Mouse Deluxe Mac or Contour Mouse */
  292         cmd = ADBLISTEN(addr, 1);
  293 
  294         /*
  295          * To setup the MicroSpeed or the Contour, it appears
  296          * that we can send the following command to the mouse
  297          * and then expect data back in the form:
  298          *  buffer[0] = 4 (bytes)
  299          *  buffer[1], buffer[2] as std. mouse
  300          *  buffer[3] = buffer[4] = 0xff when no buttons
  301          *   are down.  When button N down, bit N is clear.
  302          * buffer[4]'s locking mask enables a
  303          * click to toggle the button down state--sort of
  304          * like the "Easy Access" shift/control/etc. keys.
  305          * buffer[3]'s alternative speed mask enables using
  306          * different speed when the corr. button is down
  307          */
  308         buffer[0] = 0x00;       /* Alternative speed */
  309         buffer[1] = 0x00;       /* speed = maximum */
  310         buffer[2] = 0x10;       /* enable extended protocol,
  311                                  * lower bits = alt. speed mask
  312                                  *            = 0000b
  313                                  */
  314         buffer[3] = 0x07;       /* Locking mask = 0000b,
  315                                  * enable buttons = 0111b
  316                                  */
  317         adbms_send_sync(sc, cmd, 4, buffer);
  318 
  319         sc->sc_buttons = 3;
  320         sc->sc_res = 200;
  321 }
  322 
  323 static int
  324 adbms_turbo_csum(uint8_t *d)
  325 {
  326         int i = 0, sum = 0;
  327 
  328         for (i = 0; i < 7; i++)
  329                 sum ^= d[i];
  330         return (sum ^ 0xff);
  331 }
  332 
  333 static void
  334 adbms_init_turbo(struct adbms_softc *sc)
  335 {
  336         uint8_t addr;
  337 
  338         /* Found Kensington Turbo Mouse */
  339 
  340 /*
  341  * byte 1 assigns what which button does
  342  - 0x08 - button 1 - 1, button 2 - nothing
  343  - 0x09 - both buttons - 1
  344  - 0x0a - butoon 1 - 1, button 2 - toggle 1
  345  - 0x0b - button 1 - 1, button 2 - nothing
  346  - 0x0c - button 1 - 1, button 2 - 2
  347  - 0x0e - button 1 - 1, button 2 - 3
  348  - 0x0f - button 1 - 1, button 2 - toggle 3
  349  - 0x10 - button 1 toggle 1, button 2 nothing
  350  - 0x11 - button 1 - toggle 1, button 2 - 1
  351  - 0x12 - both toggle 1
  352  - 0x14 - button 1 toggle 1, button 2 - 2
  353  - 0x21 - button 1 - 2, button 2 - 1
  354  - 0x31 - button 1 - 3, button 2 - 1
  355  * byte 4 programs a delay for button presses, apparently in 1/100 seconds
  356  * byte 7 is a simple XOR checksum, writes will only stick if it's valid
  357           as in, b[7] = (b[0] ^ b[1] ^ ... ^ b[6]) ^ 0xff
  358  */
  359  
  360         /* this seems to be the most reasonable default */
  361         static u_char data[] =
  362                 { 0xa5, 0x0e, 0, 0, 1, 0xff, 0xff, 0/*0x55*/ };
  363 
  364         addr = sc->sc_adbdev->current_addr;
  365 
  366 #ifdef ADBMS_DEBUG
  367         {
  368                 int i;
  369                 adbms_send_sync(sc, ADBTALK(addr, 2), 0, NULL);
  370                 printf("reg *");
  371                 for (i = 0; i < sc->sc_msg_len; i++)
  372                         printf(" %02x", sc->sc_buffer[i]);
  373                 printf("\n");
  374         }
  375 #endif
  376 
  377         adbms_send_sync(sc, ADBFLUSH(addr), 0, NULL);
  378         data[7] = adbms_turbo_csum(data);
  379         adbms_send_sync(sc, ADBLISTEN(addr, 2), 8, data);
  380 
  381 
  382 #ifdef ADBMS_DEBUG
  383         int i, reg;
  384         for (reg = 1; reg < 4; reg++) {
  385                 adbms_send_sync(sc, ADBTALK(addr, reg), 0, NULL);
  386                 printf("reg %d", reg);
  387                 for (i = 0; i < sc->sc_msg_len; i++)
  388                         printf(" %02x", sc->sc_buffer[i]);
  389                 printf("\n");
  390         }
  391 #endif
  392 }
  393 
  394 static void
  395 adbms_init_mouse(struct adbms_softc *sc)
  396 {
  397         int len;
  398         uint8_t cmd, addr, buffer[16];
  399 
  400         addr = sc->sc_adbdev->current_addr;
  401         /* found a mouse */
  402         cmd = ADBTALK(addr, 3);
  403         if (!adbms_send_sync(sc, cmd, 0, NULL)) {
  404 #ifdef ADBMS_DEBUG
  405                 printf("adb: ems_init timed out\n");
  406 #endif
  407                 return;
  408         }
  409 
  410         /* Attempt to initialize Extended Mouse Protocol */
  411         len = sc->sc_msg_len;
  412         memcpy(buffer, sc->sc_buffer, len);
  413         DPRINTF("buffer: %02x %02x\n", buffer[0], buffer[1]);
  414         buffer[1] = 4; /* make handler ID 4 */
  415         cmd = ADBLISTEN(addr, 3);
  416         if (!adbms_send_sync(sc, cmd, len, buffer)) {
  417 #ifdef ADBMS_DEBUG
  418                 printf("adb: ems_init timed out\n");
  419 #endif
  420                 return;
  421         }
  422 
  423         /*
  424          * Check to see if successful, if not
  425          * try to initialize it as other types
  426          */
  427         cmd = ADBTALK(addr, 3);
  428         if (!adbms_send_sync(sc, cmd, 0, NULL)) {
  429                 DPRINTF("timeout checking for EMP switch\n");
  430                 return;
  431         }
  432         DPRINTF("new handler ID: %02x\n", sc->sc_buffer[1]);
  433         if (sc->sc_buffer[1] == ADBMS_EXTENDED) {
  434                 sc->sc_adbdev->handler_id = ADBMS_EXTENDED;
  435                 cmd = ADBTALK(addr, 1);
  436                 if(!adbms_send_sync(sc, cmd, 0, NULL)) {
  437                         DPRINTF("adb: ems_init timed out\n");
  438                         return;
  439                 }
  440 
  441                 len = sc->sc_msg_len;
  442                 memcpy(buffer, sc->sc_buffer, len);
  443 
  444                 if (sc->sc_msg_len == 8) {
  445                         uint16_t res;
  446                         /* we have a true EMP device */
  447 #ifdef ADB_PRINT_EMP
  448                 
  449                         printf("EMP: %02x %02x %02x %02x %02x %02x %02x %02x\n",
  450                             buffer[0], buffer[1], buffer[2], buffer[3],
  451                             buffer[4], buffer[5], buffer[6], buffer[7]);
  452 #endif
  453                         memcpy(sc->sc_devid, &buffer[0], 4);
  454                         memcpy(&res, &buffer[4], sizeof(res));
  455                         sc->sc_res = res;
  456                         sc->sc_class = buffer[6];
  457                         sc->sc_buttons = buffer[7];
  458                 } else if (buffer[0] == 0x9a &&
  459                     ((buffer[1] == 0x20) || (buffer[1] == 0x21))) {
  460                         /*
  461                          * Set up non-EMP Mouseman/Trackman to put
  462                          * button bits in 3rd byte instead of sending
  463                          * via pseudo keyboard device.
  464                          */
  465                         if (buffer[1] == 0x21)
  466                                 sc->sc_class = MSCLASS_TRACKBALL;
  467                         else
  468                                 sc->sc_class = MSCLASS_MOUSE;
  469 
  470                         cmd = ADBLISTEN(addr, 1);
  471                         buffer[0]=0x00;
  472                         buffer[1]=0x81;
  473                         adbms_send_sync(sc, cmd, 2, buffer);
  474 
  475                         cmd = ADBLISTEN(addr, 1);
  476                         buffer[0]=0x01;
  477                         buffer[1]=0x81;
  478                         adbms_send_sync(sc, cmd, 2, buffer);
  479 
  480                         cmd = ADBLISTEN(addr, 1);
  481                         buffer[0]=0x02;
  482                         buffer[1]=0x81;
  483                         adbms_send_sync(sc, cmd, 2, buffer);
  484 
  485                         cmd = ADBLISTEN(addr, 1);
  486                         buffer[0]=0x03;
  487                         buffer[1]=0x38;
  488                         adbms_send_sync(sc, cmd, 2, buffer);
  489 
  490                         sc->sc_buttons = 3;
  491                         sc->sc_res = 400;
  492                 }
  493         } else {
  494                 /* Attempt to initialize as an A3 mouse */
  495                 buffer[1] = 0x03; /* make handler ID 3 */
  496                 cmd = ADBLISTEN(addr, 3);
  497                 if (!adbms_send_sync(sc, cmd, len, buffer)) {
  498 #ifdef ADBMS_DEBUG
  499                         printf("adb: ems_init timed out\n");
  500 #endif
  501                         return;
  502                 }
  503 
  504                 /*
  505                  * Check to see if successful, if not
  506                  * try to initialize it as other types
  507                  */
  508                 cmd = ADBTALK(addr, 3);
  509                 if(adbms_send_sync(sc, cmd, 0, NULL)) {
  510                         len = sc->sc_msg_len;
  511                         memcpy(buffer, sc->sc_buffer, len);
  512                         if (buffer[1] == ADBMS_MSA3) {
  513                                 sc->sc_adbdev->handler_id = ADBMS_MSA3;
  514                                 /* Initialize as above */
  515                                 cmd = ADBLISTEN(addr, 2);
  516                                 /* listen 2 */
  517                                 buffer[0] = 0x00;
  518                                 /* Irrelevant, buffer has 0x77 */
  519                                 buffer[2] = 0x07;
  520                                 /*
  521                                  * enable 3 button mode = 0111b,
  522                                  * speed = normal
  523                                  */
  524                                 adbms_send_sync(sc, cmd, 3, buffer);
  525                                 sc->sc_buttons = 3;
  526                                 sc->sc_res = 300;
  527                         }
  528                 }
  529         }
  530 }
  531 
  532 static void
  533 adbms_handler(void *cookie, int len, uint8_t *data)
  534 {
  535         struct adbms_softc *sc = cookie;
  536 
  537 #ifdef ADBMS_DEBUG
  538         int i;
  539         printf("%s: %02x - ", device_xname(sc->sc_dev), sc->sc_us);
  540         for (i = 0; i < len; i++) {
  541                 printf(" %02x", data[i]);
  542         }
  543         printf("\n");
  544 #endif
  545         if (len >= 2) {
  546                 memcpy(sc->sc_buffer, &data[2], len - 2);
  547                 sc->sc_msg_len = len - 2;
  548                 if (data[1] == sc->sc_us) {
  549                         /* make sense of the mouse message */
  550                         adbms_process_event(sc, sc->sc_msg_len, sc->sc_buffer);
  551                         return;
  552                 }
  553                 wakeup(&sc->sc_event);
  554         } else {
  555                 DPRINTF("bogus message\n");
  556         }
  557 }
  558 
  559 static void
  560 adbms_process_event(struct adbms_softc *sc, int len, uint8_t *buffer)
  561 {
  562         int buttons = 0, mask, dx, dy, i;
  563         int button_bit = 1;
  564 
  565         if ((sc->sc_adbdev->handler_id == ADBMS_EXTENDED) && (sc->sc_devid[0] == 0)) {
  566                 /* massage the data to look like EMP data */
  567                 if ((buffer[2] & 0x04) == 0x04)
  568                         buffer[0] &= 0x7f;
  569                 else
  570                         buffer[0] |= 0x80;
  571                 if ((buffer[2] & 0x02) == 0x02)
  572                         buffer[1] &= 0x7f;
  573                 else
  574                         buffer[1] |= 0x80;
  575                 if ((buffer[2] & 0x01) == 0x01)
  576                         buffer[2] = 0x00;
  577                 else
  578                         buffer[2] = 0x80;
  579         }
  580 
  581         switch (sc->sc_adbdev->handler_id) {
  582                 case ADBMS_USPEED:
  583                 case ADBMS_UCONTOUR:
  584                         /* MicroSpeed mouse and Contour mouse */
  585                         if (len == 4)
  586                                 buttons = (~buffer[3]) & 0xff;
  587                         else
  588                                 buttons = (buffer[1] & 0x80) ? 0 : 1;
  589                         break;
  590                 case ADBMS_MSA3:
  591                         /* Mouse Systems A3 mouse */
  592                         if (len == 3)
  593                                 buttons = (~buffer[2]) & 0x07;
  594                         else
  595                                 buttons = (buffer[0] & 0x80) ? 0 : 1;
  596                         break;
  597                 default:        
  598                         /* Classic Mouse Protocol (up to 2 buttons) */
  599                         for (i = 0; i < 2; i++, button_bit <<= 1)
  600                                 /* 0 when button down */
  601                                 if (!(buffer[i] & 0x80))
  602                                         buttons |= button_bit;
  603                                 else
  604                                         buttons &= ~button_bit;
  605                         /* Extended Protocol (up to 6 more buttons) */
  606                         for (mask = 0x80; i < len;
  607                              i += (mask == 0x80), button_bit <<= 1) {
  608                                 /* 0 when button down */
  609                                 if (!(buffer[i] & mask))
  610                                         buttons |= button_bit;
  611                                 else
  612                                         buttons &= ~button_bit;
  613                                 mask = ((mask >> 4) & 0xf)
  614                                         | ((mask & 0xf) << 4);
  615                         }                               
  616                         break;
  617         }
  618 
  619         if ((sc->sc_adbdev->handler_id != ADBMS_EXTENDED) &&
  620             (sc->sc_adbdev->handler_id != ADBMS_TURBO)) {
  621                 dx = ((int)(buffer[1] & 0x3f)) - ((buffer[1] & 0x40) ? 64 : 0);
  622                 dy = ((int)(buffer[0] & 0x3f)) - ((buffer[0] & 0x40) ? 64 : 0);
  623         } else {
  624                 /* EMP crap, additional motion bits */
  625                 int shift = 7, ddx, ddy, sign, smask;
  626 
  627 #ifdef ADBMS_DEBUG
  628                 printf("EMP packet:");
  629                 for (i = 0; i < len; i++)
  630                         printf(" %02x", buffer[i]);
  631                 printf("\n");
  632 #endif
  633                 dx = (int)buffer[1] & 0x7f;
  634                 dy = (int)buffer[0] & 0x7f;
  635                 for (i = 2; i < len; i++) {
  636                         ddx = (buffer[i] & 0x07);
  637                         ddy = (buffer[i] & 0x70) >> 4;
  638                         dx |= (ddx << shift);
  639                         dy |= (ddy << shift);
  640                         shift += 3;
  641                 }
  642                 sign = 1 << (shift - 1);
  643                 smask = 0xffffffff << shift;
  644                 if (dx & sign)
  645                         dx |= smask;
  646                 if (dy & sign)
  647                         dy |= smask;
  648 #ifdef ADBMS_DEBUG
  649                 printf("%d %d %08x %d\n", dx, dy, smask, shift);
  650 #endif
  651         }
  652 
  653         if (sc->sc_class == MSCLASS_TRACKPAD) {
  654 
  655                 if (sc->sc_tapping == 1) {
  656                         if (sc->sc_down) {
  657                                 /* finger is down - collect motion data */
  658                                 sc->sc_x += dx;
  659                                 sc->sc_y += dy;
  660                         }
  661                         DPRINTF("buttons: %02x\n", buttons);
  662                         switch (sc->sc_buttons) {
  663                                 case 2:
  664                                         buttons |= ((buttons & 2) >> 1);
  665                                         adbms_mangle_2(sc, buttons);
  666                                         break;
  667                                 case 4:
  668                                         adbms_mangle_4(sc, buttons);
  669                                         break;
  670                         }
  671                 }
  672                 /* filter the pseudo-buttons out */
  673                 buttons &= 1;
  674         }
  675 
  676         if (sc->sc_wsmousedev)
  677                 wsmouse_input(sc->sc_wsmousedev, sc->sc_mb | buttons,
  678                               dx, -dy, 0, 0,
  679                               WSMOUSE_INPUT_DELTA);
  680 #if NAED > 0
  681         aed_input(&new_event);
  682 #endif
  683 }
  684 
  685 static void
  686 adbms_mangle_2(struct adbms_softc *sc, int buttons)
  687 {
  688 
  689         if (buttons & 4) {
  690                 /* finger down on pad */
  691                 if (sc->sc_down == 0) {
  692                         sc->sc_down = 1;
  693                         sc->sc_x = 0;
  694                         sc->sc_y = 0;
  695                 }
  696         }
  697         if (buttons & 8) {
  698                 /* finger up */
  699                 if (sc->sc_down) {
  700                         if (((sc->sc_x * sc->sc_x + 
  701                             sc->sc_y * sc->sc_y) < 3) && 
  702                             (sc->sc_wsmousedev)) {
  703                                 /* 
  704                                  * if there wasn't much movement between
  705                                  * finger down and up again we assume
  706                                  * someone tapped the pad and we just
  707                                  * send a mouse button event
  708                                  */
  709                                 wsmouse_input(sc->sc_wsmousedev,
  710                                     1, 0, 0, 0, 0, WSMOUSE_INPUT_DELTA);
  711                         }
  712                         sc->sc_down = 0;
  713                 }
  714         }
  715 }
  716 
  717 static void
  718 adbms_mangle_4(struct adbms_softc *sc, int buttons)
  719 {
  720 
  721         if (buttons & 0x20) {
  722                 /* finger down on pad */
  723                 if (sc->sc_down == 0) {
  724                         sc->sc_down = 1;
  725                         sc->sc_x = 0;
  726                         sc->sc_y = 0;
  727                 }
  728         }
  729         if ((buttons & 0x20) == 0) {
  730                 /* finger up */
  731                 if (sc->sc_down) {
  732                         if (((sc->sc_x * sc->sc_x + 
  733                             sc->sc_y * sc->sc_y) < 3) && 
  734                             (sc->sc_wsmousedev)) {
  735                                 /* 
  736                                  * if there wasn't much movement between
  737                                  * finger down and up again we assume
  738                                  * someone tapped the pad and we just
  739                                  * send a mouse button event
  740                                  */
  741                                 wsmouse_input(sc->sc_wsmousedev,
  742                                     1, 0, 0, 0, 0, WSMOUSE_INPUT_DELTA);
  743                         }
  744                         sc->sc_down = 0;
  745                 }
  746         }
  747 }
  748 
  749 static int
  750 adbms_enable(void *v)
  751 {
  752         return 0;
  753 }
  754 
  755 static int
  756 adbms_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
  757 {
  758 
  759         switch (cmd) {
  760         case WSMOUSEIO_GTYPE:
  761                 *(u_int *)data = WSMOUSE_TYPE_ADB;
  762                 break;
  763 
  764         default:
  765                 return (EPASSTHROUGH);
  766         }
  767         return (0);
  768 }
  769 
  770 static void
  771 adbms_disable(void *v)
  772 {
  773 }
  774 
  775 static void
  776 init_trackpad(struct adbms_softc *sc)
  777 {
  778         const struct sysctlnode *me = NULL, *node = NULL;
  779         int cmd, addr, ret;
  780         uint8_t buffer[16];
  781         uint8_t b2[] = {0x99, 0x94, 0x19, 0xff, 0xb2, 0x8a, 0x1b, 0x50};
  782         
  783         addr = sc->sc_adbdev->current_addr;
  784         cmd = ADBTALK(addr, 1);
  785         if (!adbms_send_sync(sc, cmd, 0, NULL))
  786                 return;
  787 
  788         if (sc->sc_msg_len != 8)
  789                 return;
  790 
  791         memcpy(buffer, sc->sc_buffer, 8);
  792 
  793         /* now whack the pad */
  794         cmd = ADBLISTEN(addr, 1);
  795         buffer[6] = 0x0d;
  796         adbms_send_sync(sc, cmd, 8, buffer);
  797 
  798         delay(1000);
  799         cmd = ADBLISTEN(addr, 2);
  800         adbms_send_sync(sc, cmd, 8, b2);
  801 
  802         delay(1000);
  803         cmd = ADBLISTEN(addr, 1);
  804         buffer[6] = 0x03;
  805         adbms_send_sync(sc, cmd, 8, buffer);
  806 
  807         cmd = ADBFLUSH(addr);
  808         adbms_send_sync(sc, cmd, 0, NULL);
  809         delay(1000);
  810 
  811         /*
  812          * setup a sysctl node to control whether tapping the pad should
  813          * trigger mouse button events
  814          */
  815 
  816         sc->sc_tapping = 1;
  817         
  818         ret = sysctl_createv(NULL, 0, NULL, &me,
  819             CTLFLAG_READWRITE,
  820             CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
  821             NULL, 0, NULL, 0,
  822             CTL_MACHDEP, CTL_CREATE, CTL_EOL);
  823 
  824         ret = sysctl_createv(NULL, 0, NULL, &node,
  825             CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
  826             CTLTYPE_INT, "tapping", "tapping the pad causes button events",
  827             sysctl_adbms_tap, 1, (void *)sc, 0,
  828             CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
  829 
  830         (void)ret;
  831 }
  832 
  833 static int
  834 adbms_wait(struct adbms_softc *sc, int timeout)
  835 {
  836         int cnt = 0;
  837         
  838         if (sc->sc_poll) {
  839                 while (sc->sc_msg_len == -1) {
  840                         sc->sc_ops->poll(sc->sc_ops->cookie);
  841                 }
  842         } else {
  843                 while ((sc->sc_msg_len == -1) && (cnt < timeout)) {
  844                         tsleep(&sc->sc_event, 0, "adbmsio", hz);
  845                         cnt++;
  846                 }
  847         }
  848         return (sc->sc_msg_len > 0);
  849 }
  850 
  851 static int
  852 adbms_send_sync(struct adbms_softc *sc, uint8_t cmd, int len, uint8_t *msg)
  853 {
  854         int i;
  855 
  856         sc->sc_msg_len = -1;
  857         DPRINTF("send: %02x", cmd);
  858         for (i = 0; i < len; i++)
  859                 DPRINTF(" %02x", msg[i]);
  860         DPRINTF("\n");
  861         sc->sc_ops->send(sc->sc_ops->cookie, sc->sc_poll, cmd, len, msg);
  862         adbms_wait(sc, 3);
  863         return (sc->sc_msg_len != -1);
  864 }
  865 
  866 static int
  867 sysctl_adbms_tap(SYSCTLFN_ARGS)
  868 {
  869         struct sysctlnode node = *rnode;
  870         struct adbms_softc *sc = node.sysctl_data;
  871 
  872         node.sysctl_idata = sc->sc_tapping;
  873 
  874         if (newp) {
  875 
  876                 /* we're asked to write */      
  877                 node.sysctl_data = &sc->sc_tapping;
  878                 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
  879 
  880                         sc->sc_tapping = (*(int *)node.sysctl_data == 0) ? 0 : 1;
  881                         return 0;
  882                 }
  883                 return EINVAL;
  884         } else {
  885 
  886                 node.sysctl_data = &sc->sc_tapping;
  887                 node.sysctl_size = 4;
  888                 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
  889         }
  890 
  891         return 0;
  892 }
  893 
  894 SYSCTL_SETUP(sysctl_ams_setup, "sysctl ams subtree setup")
  895 {
  896 
  897         sysctl_createv(NULL, 0, NULL, NULL,
  898                        CTLFLAG_PERMANENT,
  899                        CTLTYPE_NODE, "machdep", NULL,
  900                        NULL, 0, NULL, 0,
  901                        CTL_MACHDEP, CTL_EOL);
  902 }

Cache object: 8f428b25bc2da07ca39cbf8784d32409


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