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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: 0c7c5623b9742e5bb7619b7650458a68


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