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/usb/input/ums.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 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Lennart Augustsson (lennart@augustsson.net) at
    9  * Carlstedt Research & Technology.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 /*
   37  * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
   38  */
   39 
   40 #include "opt_evdev.h"
   41 
   42 #include <sys/stdint.h>
   43 #include <sys/stddef.h>
   44 #include <sys/param.h>
   45 #include <sys/queue.h>
   46 #include <sys/types.h>
   47 #include <sys/systm.h>
   48 #include <sys/kernel.h>
   49 #include <sys/bus.h>
   50 #include <sys/module.h>
   51 #include <sys/lock.h>
   52 #include <sys/mutex.h>
   53 #include <sys/condvar.h>
   54 #include <sys/sysctl.h>
   55 #include <sys/sx.h>
   56 #include <sys/unistd.h>
   57 #include <sys/callout.h>
   58 #include <sys/malloc.h>
   59 #include <sys/priv.h>
   60 #include <sys/conf.h>
   61 #include <sys/fcntl.h>
   62 #include <sys/sbuf.h>
   63 
   64 #include <dev/hid/hid.h>
   65 
   66 #include <dev/usb/usb.h>
   67 #include <dev/usb/usbdi.h>
   68 #include <dev/usb/usbdi_util.h>
   69 #include <dev/usb/usbhid.h>
   70 #include "usbdevs.h"
   71 
   72 #define USB_DEBUG_VAR ums_debug
   73 #include <dev/usb/usb_debug.h>
   74 
   75 #include <dev/usb/quirk/usb_quirk.h>
   76 
   77 #ifdef EVDEV_SUPPORT
   78 #include <dev/evdev/input.h>
   79 #include <dev/evdev/evdev.h>
   80 #endif
   81 
   82 #include <sys/ioccom.h>
   83 #include <sys/filio.h>
   84 #include <sys/mouse.h>
   85 
   86 #ifdef USB_DEBUG
   87 static int ums_debug = 0;
   88 
   89 static SYSCTL_NODE(_hw_usb, OID_AUTO, ums, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
   90     "USB ums");
   91 SYSCTL_INT(_hw_usb_ums, OID_AUTO, debug, CTLFLAG_RWTUN,
   92     &ums_debug, 0, "Debug level");
   93 #endif
   94 
   95 #define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE)
   96 #define MOUSE_FLAGS (HIO_RELATIVE)
   97 
   98 #define UMS_BUF_SIZE      8             /* bytes */
   99 #define UMS_IFQ_MAXLEN   50             /* units */
  100 #define UMS_BUTTON_MAX   31             /* exclusive, must be less than 32 */
  101 #define UMS_BUT(i) ((i) < 3 ? (((i) + 2) % 3) : (i))
  102 #define UMS_INFO_MAX      2             /* maximum number of HID sets */
  103 
  104 enum {
  105         UMS_INTR_DT,
  106         UMS_N_TRANSFER,
  107 };
  108 
  109 struct ums_info {
  110         struct hid_location sc_loc_w;
  111         struct hid_location sc_loc_x;
  112         struct hid_location sc_loc_y;
  113         struct hid_location sc_loc_z;
  114         struct hid_location sc_loc_t;
  115         struct hid_location sc_loc_btn[UMS_BUTTON_MAX];
  116 
  117         uint32_t sc_flags;
  118 #define UMS_FLAG_X_AXIS     0x0001
  119 #define UMS_FLAG_Y_AXIS     0x0002
  120 #define UMS_FLAG_Z_AXIS     0x0004
  121 #define UMS_FLAG_T_AXIS     0x0008
  122 #define UMS_FLAG_SBU        0x0010      /* spurious button up events */
  123 #define UMS_FLAG_REVZ       0x0020      /* Z-axis is reversed */
  124 #define UMS_FLAG_W_AXIS     0x0040
  125 #define UMS_FLAG_VBTN       0x0080      /* Buttons in vendor usage page */
  126 
  127         uint8_t sc_iid_w;
  128         uint8_t sc_iid_x;
  129         uint8_t sc_iid_y;
  130         uint8_t sc_iid_z;
  131         uint8_t sc_iid_t;
  132         uint8_t sc_iid_btn[UMS_BUTTON_MAX];
  133         uint8_t sc_buttons;
  134 };
  135 
  136 struct ums_softc {
  137         struct usb_fifo_sc sc_fifo;
  138         struct mtx sc_mtx;
  139         struct usb_callout sc_callout;
  140         struct ums_info sc_info[UMS_INFO_MAX];
  141 
  142         mousehw_t sc_hw;
  143         mousemode_t sc_mode;
  144         mousestatus_t sc_status;
  145 
  146         struct usb_xfer *sc_xfer[UMS_N_TRANSFER];
  147 
  148         int sc_pollrate;
  149         int sc_fflags;
  150 #ifdef EVDEV_SUPPORT
  151         int sc_evflags;
  152 #define UMS_EVDEV_OPENED        1
  153 #endif
  154 
  155         uint8_t sc_buttons;
  156         uint8_t sc_iid;
  157         uint8_t sc_temp[64];
  158 
  159 #ifdef EVDEV_SUPPORT
  160         struct evdev_dev *sc_evdev;
  161 #endif
  162 };
  163 
  164 static void ums_put_queue_timeout(void *__sc);
  165 
  166 static usb_callback_t ums_intr_callback;
  167 
  168 static device_probe_t ums_probe;
  169 static device_attach_t ums_attach;
  170 static device_detach_t ums_detach;
  171 
  172 static usb_fifo_cmd_t ums_fifo_start_read;
  173 static usb_fifo_cmd_t ums_fifo_stop_read;
  174 static usb_fifo_open_t ums_fifo_open;
  175 static usb_fifo_close_t ums_fifo_close;
  176 static usb_fifo_ioctl_t ums_fifo_ioctl;
  177 
  178 #ifdef EVDEV_SUPPORT
  179 static evdev_open_t ums_ev_open;
  180 static evdev_close_t ums_ev_close;
  181 static void ums_evdev_push(struct ums_softc *, int32_t, int32_t,
  182     int32_t, int32_t, int32_t);
  183 #endif
  184 
  185 static void     ums_start_rx(struct ums_softc *);
  186 static void     ums_stop_rx(struct ums_softc *);
  187 static void     ums_put_queue(struct ums_softc *, int32_t, int32_t,
  188                     int32_t, int32_t, int32_t);
  189 static int      ums_sysctl_handler_parseinfo(SYSCTL_HANDLER_ARGS);
  190 
  191 static struct usb_fifo_methods ums_fifo_methods = {
  192         .f_open = &ums_fifo_open,
  193         .f_close = &ums_fifo_close,
  194         .f_ioctl = &ums_fifo_ioctl,
  195         .f_start_read = &ums_fifo_start_read,
  196         .f_stop_read = &ums_fifo_stop_read,
  197         .basename[0] = "ums",
  198 };
  199 
  200 #ifdef EVDEV_SUPPORT
  201 static const struct evdev_methods ums_evdev_methods = {
  202         .ev_open = &ums_ev_open,
  203         .ev_close = &ums_ev_close,
  204 };
  205 #endif
  206 
  207 static void
  208 ums_put_queue_timeout(void *__sc)
  209 {
  210         struct ums_softc *sc = __sc;
  211 
  212         mtx_assert(&sc->sc_mtx, MA_OWNED);
  213 
  214         ums_put_queue(sc, 0, 0, 0, 0, 0);
  215 #ifdef EVDEV_SUPPORT
  216         ums_evdev_push(sc, 0, 0, 0, 0, 0);
  217 #endif
  218 }
  219 
  220 static void
  221 ums_intr_callback(struct usb_xfer *xfer, usb_error_t error)
  222 {
  223         struct ums_softc *sc = usbd_xfer_softc(xfer);
  224         struct ums_info *info = &sc->sc_info[0];
  225         struct usb_page_cache *pc;
  226         uint8_t *buf = sc->sc_temp;
  227         int32_t buttons = 0;
  228         int32_t buttons_found = 0;
  229 #ifdef EVDEV_SUPPORT
  230         int32_t buttons_reported = 0;
  231 #endif
  232         int32_t dw = 0;
  233         int32_t dx = 0;
  234         int32_t dy = 0;
  235         int32_t dz = 0;
  236         int32_t dt = 0;
  237         uint8_t i;
  238         uint8_t id;
  239         int len;
  240 
  241         usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
  242 
  243         switch (USB_GET_STATE(xfer)) {
  244         case USB_ST_TRANSFERRED:
  245                 DPRINTFN(6, "sc=%p actlen=%d\n", sc, len);
  246 
  247                 if (len > (int)sizeof(sc->sc_temp)) {
  248                         DPRINTFN(6, "truncating large packet to %zu bytes\n",
  249                             sizeof(sc->sc_temp));
  250                         len = sizeof(sc->sc_temp);
  251                 }
  252                 if (len == 0)
  253                         goto tr_setup;
  254 
  255                 pc = usbd_xfer_get_frame(xfer, 0);
  256                 usbd_copy_out(pc, 0, buf, len);
  257 
  258                 DPRINTFN(6, "data = %02x %02x %02x %02x "
  259                     "%02x %02x %02x %02x\n",
  260                     (len > 0) ? buf[0] : 0, (len > 1) ? buf[1] : 0,
  261                     (len > 2) ? buf[2] : 0, (len > 3) ? buf[3] : 0,
  262                     (len > 4) ? buf[4] : 0, (len > 5) ? buf[5] : 0,
  263                     (len > 6) ? buf[6] : 0, (len > 7) ? buf[7] : 0);
  264 
  265                 if (sc->sc_iid) {
  266                         id = *buf;
  267 
  268                         len--;
  269                         buf++;
  270 
  271                 } else {
  272                         id = 0;
  273                         if (sc->sc_info[0].sc_flags & UMS_FLAG_SBU) {
  274                                 if ((*buf == 0x14) || (*buf == 0x15)) {
  275                                         goto tr_setup;
  276                                 }
  277                         }
  278                 }
  279 
  280         repeat:
  281                 if ((info->sc_flags & UMS_FLAG_W_AXIS) &&
  282                     (id == info->sc_iid_w))
  283                         dw += hid_get_data(buf, len, &info->sc_loc_w);
  284 
  285                 if ((info->sc_flags & UMS_FLAG_X_AXIS) && 
  286                     (id == info->sc_iid_x))
  287                         dx += hid_get_data(buf, len, &info->sc_loc_x);
  288 
  289                 if ((info->sc_flags & UMS_FLAG_Y_AXIS) &&
  290                     (id == info->sc_iid_y))
  291                         dy -= hid_get_data(buf, len, &info->sc_loc_y);
  292 
  293                 if ((info->sc_flags & UMS_FLAG_Z_AXIS) &&
  294                     (id == info->sc_iid_z)) {
  295                         int32_t temp;
  296                         temp = hid_get_data(buf, len, &info->sc_loc_z);
  297                         if (info->sc_flags & UMS_FLAG_REVZ)
  298                                 temp = -temp;
  299                         dz -= temp;
  300                 }
  301 
  302                 if ((info->sc_flags & UMS_FLAG_T_AXIS) &&
  303                     (id == info->sc_iid_t)) {
  304                         dt += hid_get_data(buf, len, &info->sc_loc_t);
  305                         /* T-axis is translated into button presses */
  306                         buttons_found |= (1UL << 5) | (1UL << 6);
  307                 }
  308 
  309                 for (i = 0; i < info->sc_buttons; i++) {
  310                         uint32_t mask;
  311                         mask = 1UL << UMS_BUT(i);
  312                         /* check for correct button ID */
  313                         if (id != info->sc_iid_btn[i])
  314                                 continue;
  315                         /* check for button pressed */
  316                         if (hid_get_data(buf, len, &info->sc_loc_btn[i]))
  317                                 buttons |= mask;
  318                         /* register button mask */
  319                         buttons_found |= mask;
  320                 }
  321 
  322                 if (++info != &sc->sc_info[UMS_INFO_MAX])
  323                         goto repeat;
  324 
  325 #ifdef EVDEV_SUPPORT
  326                 buttons_reported = buttons;
  327 #endif
  328                 /* keep old button value(s) for non-detected buttons */
  329                 buttons |= sc->sc_status.button & ~buttons_found;
  330 
  331                 if (dx || dy || dz || dt || dw ||
  332                     (buttons != sc->sc_status.button)) {
  333                         DPRINTFN(6, "x:%d y:%d z:%d t:%d w:%d buttons:0x%08x\n",
  334                             dx, dy, dz, dt, dw, buttons);
  335 
  336                         /* translate T-axis into button presses until further */
  337                         if (dt > 0) {
  338                                 ums_put_queue(sc, 0, 0, 0, 0, buttons);
  339                                 buttons |= 1UL << 6;
  340                         } else if (dt < 0) {
  341                                 ums_put_queue(sc, 0, 0, 0, 0, buttons);
  342                                 buttons |= 1UL << 5;
  343                         }
  344 
  345                         sc->sc_status.button = buttons;
  346                         sc->sc_status.dx += dx;
  347                         sc->sc_status.dy += dy;
  348                         sc->sc_status.dz += dz;
  349                         /*
  350                          * sc->sc_status.dt += dt;
  351                          * no way to export this yet
  352                          */
  353 
  354                         /*
  355                          * The Qtronix keyboard has a built in PS/2
  356                          * port for a mouse.  The firmware once in a
  357                          * while posts a spurious button up
  358                          * event. This event we ignore by doing a
  359                          * timeout for 50 msecs.  If we receive
  360                          * dx=dy=dz=buttons=0 before we add the event
  361                          * to the queue.  In any other case we delete
  362                          * the timeout event.
  363                          */
  364                         if ((sc->sc_info[0].sc_flags & UMS_FLAG_SBU) &&
  365                             (dx == 0) && (dy == 0) && (dz == 0) && (dt == 0) &&
  366                             (dw == 0) && (buttons == 0)) {
  367                                 usb_callout_reset(&sc->sc_callout, hz / 20,
  368                                     &ums_put_queue_timeout, sc);
  369                         } else {
  370                                 usb_callout_stop(&sc->sc_callout);
  371 
  372                                 ums_put_queue(sc, dx, dy, dz, dt, buttons);
  373 #ifdef EVDEV_SUPPORT
  374                                 ums_evdev_push(sc, dx, dy, dz, dt,
  375                                     buttons_reported);
  376 #endif
  377                         }
  378                 }
  379         case USB_ST_SETUP:
  380 tr_setup:
  381                 /* check if we can put more data into the FIFO */
  382                 if (usb_fifo_put_bytes_max(sc->sc_fifo.fp[USB_FIFO_RX]) == 0) {
  383 #ifdef EVDEV_SUPPORT
  384                         if ((sc->sc_evflags & UMS_EVDEV_OPENED) == 0)
  385                                 break;
  386 #else
  387                         break;
  388 #endif
  389                 }
  390 
  391                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
  392                 usbd_transfer_submit(xfer);
  393                 break;
  394 
  395         default:                        /* Error */
  396                 if (error != USB_ERR_CANCELLED) {
  397                         /* try clear stall first */
  398                         usbd_xfer_set_stall(xfer);
  399                         goto tr_setup;
  400                 }
  401                 break;
  402         }
  403 }
  404 
  405 static const struct usb_config ums_config[UMS_N_TRANSFER] = {
  406         [UMS_INTR_DT] = {
  407                 .type = UE_INTERRUPT,
  408                 .endpoint = UE_ADDR_ANY,
  409                 .direction = UE_DIR_IN,
  410                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
  411                 .bufsize = 0,   /* use wMaxPacketSize */
  412                 .callback = &ums_intr_callback,
  413         },
  414 };
  415 
  416 /* A match on these entries will load ums */
  417 static const STRUCT_USB_HOST_ID __used ums_devs[] = {
  418         {USB_IFACE_CLASS(UICLASS_HID),
  419          USB_IFACE_SUBCLASS(UISUBCLASS_BOOT),
  420          USB_IFACE_PROTOCOL(UIPROTO_MOUSE),},
  421 };
  422 
  423 static int
  424 ums_probe(device_t dev)
  425 {
  426         struct usb_attach_arg *uaa = device_get_ivars(dev);
  427         void *d_ptr;
  428         int error;
  429         uint16_t d_len;
  430 
  431         DPRINTFN(11, "\n");
  432 
  433         if (uaa->usb_mode != USB_MODE_HOST)
  434                 return (ENXIO);
  435 
  436         if (uaa->info.bInterfaceClass != UICLASS_HID)
  437                 return (ENXIO);
  438 
  439         if (usb_test_quirk(uaa, UQ_UMS_IGNORE))
  440                 return (ENXIO);
  441 
  442         if ((uaa->info.bInterfaceSubClass == UISUBCLASS_BOOT) &&
  443             (uaa->info.bInterfaceProtocol == UIPROTO_MOUSE))
  444                 return (BUS_PROBE_DEFAULT);
  445 
  446         error = usbd_req_get_hid_desc(uaa->device, NULL,
  447             &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex);
  448 
  449         if (error)
  450                 return (ENXIO);
  451 
  452         if (hid_is_mouse(d_ptr, d_len))
  453                 error = BUS_PROBE_DEFAULT;
  454         else
  455                 error = ENXIO;
  456 
  457         free(d_ptr, M_TEMP);
  458         return (error);
  459 }
  460 
  461 static void
  462 ums_hid_parse(struct ums_softc *sc, device_t dev, const uint8_t *buf,
  463     uint16_t len, uint8_t index)
  464 {
  465         struct ums_info *info = &sc->sc_info[index];
  466         uint32_t flags;
  467         uint8_t i;
  468         uint8_t j;
  469 
  470         if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
  471             hid_input, index, &info->sc_loc_x, &flags, &info->sc_iid_x)) {
  472                 if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
  473                         info->sc_flags |= UMS_FLAG_X_AXIS;
  474                 }
  475         }
  476         if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
  477             hid_input, index, &info->sc_loc_y, &flags, &info->sc_iid_y)) {
  478                 if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
  479                         info->sc_flags |= UMS_FLAG_Y_AXIS;
  480                 }
  481         }
  482         /* Try the wheel first as the Z activator since it's tradition. */
  483         if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
  484             HUG_WHEEL), hid_input, index, &info->sc_loc_z, &flags,
  485             &info->sc_iid_z) ||
  486             hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
  487             HUG_TWHEEL), hid_input, index, &info->sc_loc_z, &flags,
  488             &info->sc_iid_z)) {
  489                 if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
  490                         info->sc_flags |= UMS_FLAG_Z_AXIS;
  491                 }
  492                 /*
  493                  * We might have both a wheel and Z direction, if so put
  494                  * put the Z on the W coordinate.
  495                  */
  496                 if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
  497                     HUG_Z), hid_input, index, &info->sc_loc_w, &flags,
  498                     &info->sc_iid_w)) {
  499                         if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
  500                                 info->sc_flags |= UMS_FLAG_W_AXIS;
  501                         }
  502                 }
  503         } else if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
  504             HUG_Z), hid_input, index, &info->sc_loc_z, &flags, 
  505             &info->sc_iid_z)) {
  506                 if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
  507                         info->sc_flags |= UMS_FLAG_Z_AXIS;
  508                 }
  509         }
  510         /*
  511          * The Microsoft Wireless Intellimouse 2.0 reports it's wheel
  512          * using 0x0048, which is HUG_TWHEEL, and seems to expect you
  513          * to know that the byte after the wheel is the tilt axis.
  514          * There are no other HID axis descriptors other than X,Y and
  515          * TWHEEL
  516          */
  517         if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
  518             HUG_TWHEEL), hid_input, index, &info->sc_loc_t, 
  519             &flags, &info->sc_iid_t)) {
  520                 info->sc_loc_t.pos += 8;
  521 
  522                 if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS) {
  523                         info->sc_flags |= UMS_FLAG_T_AXIS;
  524                 }
  525         } else if (hid_locate(buf, len, HID_USAGE2(HUP_CONSUMER,
  526                 HUC_AC_PAN), hid_input, index, &info->sc_loc_t,
  527                 &flags, &info->sc_iid_t)) {
  528                 if ((flags & MOUSE_FLAGS_MASK) == MOUSE_FLAGS)
  529                         info->sc_flags |= UMS_FLAG_T_AXIS;
  530         }
  531         /* figure out the number of buttons */
  532 
  533         for (i = 0; i < UMS_BUTTON_MAX; i++) {
  534                 if (!hid_locate(buf, len, HID_USAGE2(HUP_BUTTON, (i + 1)),
  535                     hid_input, index, &info->sc_loc_btn[i], NULL, 
  536                     &info->sc_iid_btn[i])) {
  537                         break;
  538                 }
  539         }
  540 
  541         /* detect other buttons */
  542         if (info->sc_flags & UMS_FLAG_VBTN) {
  543                 for (j = 0; (i < UMS_BUTTON_MAX) && (j < 2); i++, j++) {
  544                         if (!hid_locate(buf, len, HID_USAGE2(HUP_MICROSOFT,
  545                             (j + 1)), hid_input, index, &info->sc_loc_btn[i],
  546                             NULL, &info->sc_iid_btn[i])) {
  547                                 break;
  548                         }
  549                 }
  550         }
  551 
  552         info->sc_buttons = i;
  553 
  554         if (i > sc->sc_buttons)
  555                 sc->sc_buttons = i;
  556 
  557         if (info->sc_flags == 0)
  558                 return;
  559 
  560         /* announce information about the mouse */
  561         device_printf(dev, "%d buttons and [%s%s%s%s%s] coordinates ID=%u\n",
  562             (info->sc_buttons),
  563             (info->sc_flags & UMS_FLAG_X_AXIS) ? "X" : "",
  564             (info->sc_flags & UMS_FLAG_Y_AXIS) ? "Y" : "",
  565             (info->sc_flags & UMS_FLAG_Z_AXIS) ? "Z" : "",
  566             (info->sc_flags & UMS_FLAG_T_AXIS) ? "T" : "",
  567             (info->sc_flags & UMS_FLAG_W_AXIS) ? "W" : "",
  568             info->sc_iid_x);
  569 }
  570 
  571 static int
  572 ums_attach(device_t dev)
  573 {
  574         struct usb_attach_arg *uaa = device_get_ivars(dev);
  575         struct ums_softc *sc = device_get_softc(dev);
  576         struct ums_info *info;
  577         void *d_ptr = NULL;
  578         int isize;
  579         int err;
  580         uint16_t d_len;
  581         uint8_t i;
  582 #ifdef USB_DEBUG
  583         uint8_t j;
  584 #endif
  585 
  586         DPRINTFN(11, "sc=%p\n", sc);
  587 
  588         device_set_usb_desc(dev);
  589 
  590         mtx_init(&sc->sc_mtx, "ums lock", NULL, MTX_DEF | MTX_RECURSE);
  591 
  592         usb_callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0);
  593 
  594         /*
  595          * Force the report (non-boot) protocol.
  596          *
  597          * Mice without boot protocol support may choose not to implement
  598          * Set_Protocol at all; Ignore any error.
  599          */
  600         err = usbd_req_set_protocol(uaa->device, NULL,
  601             uaa->info.bIfaceIndex, 1);
  602 
  603         err = usbd_transfer_setup(uaa->device,
  604             &uaa->info.bIfaceIndex, sc->sc_xfer, ums_config,
  605             UMS_N_TRANSFER, sc, &sc->sc_mtx);
  606 
  607         if (err) {
  608                 DPRINTF("error=%s\n", usbd_errstr(err));
  609                 goto detach;
  610         }
  611 
  612         /* Get HID descriptor */
  613         err = usbd_req_get_hid_desc(uaa->device, NULL, &d_ptr,
  614             &d_len, M_TEMP, uaa->info.bIfaceIndex);
  615 
  616         if (err) {
  617                 device_printf(dev, "error reading report description\n");
  618                 goto detach;
  619         }
  620 
  621         isize = hid_report_size_max(d_ptr, d_len, hid_input, &sc->sc_iid);
  622 
  623         if (usb_test_quirk(uaa, UQ_MS_VENDOR_BTN))
  624                 for (i = 0; i < UMS_INFO_MAX; i++)
  625                         sc->sc_info[i].sc_flags |= UMS_FLAG_VBTN;
  626 
  627         /*
  628          * The Microsoft Wireless Notebook Optical Mouse seems to be in worse
  629          * shape than the Wireless Intellimouse 2.0, as its X, Y, wheel, and
  630          * all of its other button positions are all off. It also reports that
  631          * it has two additional buttons and a tilt wheel.
  632          */
  633         if (usb_test_quirk(uaa, UQ_MS_BAD_CLASS)) {
  634                 sc->sc_iid = 0;
  635 
  636                 info = &sc->sc_info[0];
  637                 info->sc_flags = (UMS_FLAG_X_AXIS |
  638                     UMS_FLAG_Y_AXIS |
  639                     UMS_FLAG_Z_AXIS |
  640                     UMS_FLAG_SBU);
  641                 info->sc_buttons = 3;
  642                 isize = 5;
  643                 /* 1st byte of descriptor report contains garbage */
  644                 info->sc_loc_x.pos = 16;
  645                 info->sc_loc_x.size = 8;
  646                 info->sc_loc_y.pos = 24;
  647                 info->sc_loc_y.size = 8;
  648                 info->sc_loc_z.pos = 32;
  649                 info->sc_loc_z.size = 8;
  650                 info->sc_loc_btn[0].pos = 8;
  651                 info->sc_loc_btn[0].size = 1;
  652                 info->sc_loc_btn[1].pos = 9;
  653                 info->sc_loc_btn[1].size = 1;
  654                 info->sc_loc_btn[2].pos = 10;
  655                 info->sc_loc_btn[2].size = 1;
  656 
  657                 /* Announce device */
  658                 device_printf(dev, "3 buttons and [XYZ] "
  659                     "coordinates ID=0\n");
  660 
  661         } else {
  662                 /* Search the HID descriptor and announce device */
  663                 for (i = 0; i < UMS_INFO_MAX; i++) {
  664                         ums_hid_parse(sc, dev, d_ptr, d_len, i);
  665                 }
  666         }
  667 
  668         if (usb_test_quirk(uaa, UQ_MS_REVZ)) {
  669                 info = &sc->sc_info[0];
  670                 /* Some wheels need the Z axis reversed. */
  671                 info->sc_flags |= UMS_FLAG_REVZ;
  672         }
  673         if (isize > (int)usbd_xfer_max_framelen(sc->sc_xfer[UMS_INTR_DT])) {
  674                 DPRINTF("WARNING: report size, %d bytes, is larger "
  675                     "than interrupt size, %d bytes!\n", isize,
  676                     usbd_xfer_max_framelen(sc->sc_xfer[UMS_INTR_DT]));
  677         }
  678         free(d_ptr, M_TEMP);
  679         d_ptr = NULL;
  680 
  681 #ifdef USB_DEBUG
  682         for (j = 0; j < UMS_INFO_MAX; j++) {
  683                 info = &sc->sc_info[j];
  684 
  685                 DPRINTF("sc=%p, index=%d\n", sc, j);
  686                 DPRINTF("X\t%d/%d id=%d\n", info->sc_loc_x.pos,
  687                     info->sc_loc_x.size, info->sc_iid_x);
  688                 DPRINTF("Y\t%d/%d id=%d\n", info->sc_loc_y.pos,
  689                     info->sc_loc_y.size, info->sc_iid_y);
  690                 DPRINTF("Z\t%d/%d id=%d\n", info->sc_loc_z.pos,
  691                     info->sc_loc_z.size, info->sc_iid_z);
  692                 DPRINTF("T\t%d/%d id=%d\n", info->sc_loc_t.pos,
  693                     info->sc_loc_t.size, info->sc_iid_t);
  694                 DPRINTF("W\t%d/%d id=%d\n", info->sc_loc_w.pos,
  695                     info->sc_loc_w.size, info->sc_iid_w);
  696 
  697                 for (i = 0; i < info->sc_buttons; i++) {
  698                         DPRINTF("B%d\t%d/%d id=%d\n",
  699                             i + 1, info->sc_loc_btn[i].pos,
  700                             info->sc_loc_btn[i].size, info->sc_iid_btn[i]);
  701                 }
  702         }
  703         DPRINTF("size=%d, id=%d\n", isize, sc->sc_iid);
  704 #endif
  705 
  706         err = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx,
  707             &ums_fifo_methods, &sc->sc_fifo,
  708             device_get_unit(dev), -1, uaa->info.bIfaceIndex,
  709             UID_ROOT, GID_OPERATOR, 0644);
  710         if (err)
  711                 goto detach;
  712 
  713 #ifdef EVDEV_SUPPORT
  714         sc->sc_evdev = evdev_alloc();
  715         evdev_set_name(sc->sc_evdev, device_get_desc(dev));
  716         evdev_set_phys(sc->sc_evdev, device_get_nameunit(dev));
  717         evdev_set_id(sc->sc_evdev, BUS_USB, uaa->info.idVendor,
  718             uaa->info.idProduct, 0);
  719         evdev_set_serial(sc->sc_evdev, usb_get_serial(uaa->device));
  720         evdev_set_methods(sc->sc_evdev, sc, &ums_evdev_methods);
  721         evdev_support_prop(sc->sc_evdev, INPUT_PROP_POINTER);
  722         evdev_support_event(sc->sc_evdev, EV_SYN);
  723         evdev_support_event(sc->sc_evdev, EV_REL);
  724         evdev_support_event(sc->sc_evdev, EV_KEY);
  725 
  726         info = &sc->sc_info[0];
  727 
  728         if (info->sc_flags & UMS_FLAG_X_AXIS)
  729                 evdev_support_rel(sc->sc_evdev, REL_X);
  730 
  731         if (info->sc_flags & UMS_FLAG_Y_AXIS)
  732                 evdev_support_rel(sc->sc_evdev, REL_Y);
  733 
  734         if (info->sc_flags & UMS_FLAG_Z_AXIS)
  735                 evdev_support_rel(sc->sc_evdev, REL_WHEEL);
  736 
  737         if (info->sc_flags & UMS_FLAG_T_AXIS)
  738                 evdev_support_rel(sc->sc_evdev, REL_HWHEEL);
  739 
  740         for (i = 0; i < info->sc_buttons; i++)
  741                 evdev_support_key(sc->sc_evdev, BTN_MOUSE + i);
  742 
  743         err = evdev_register_mtx(sc->sc_evdev, &sc->sc_mtx);
  744         if (err)
  745                 goto detach;
  746 #endif
  747 
  748         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
  749             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
  750             OID_AUTO, "parseinfo",
  751             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
  752             sc, 0, ums_sysctl_handler_parseinfo, "",
  753             "Dump of parsed HID report descriptor");
  754 
  755         return (0);
  756 
  757 detach:
  758         if (d_ptr) {
  759                 free(d_ptr, M_TEMP);
  760         }
  761         ums_detach(dev);
  762         return (ENOMEM);
  763 }
  764 
  765 static int
  766 ums_detach(device_t self)
  767 {
  768         struct ums_softc *sc = device_get_softc(self);
  769 
  770         DPRINTF("sc=%p\n", sc);
  771 
  772         usb_fifo_detach(&sc->sc_fifo);
  773 
  774 #ifdef EVDEV_SUPPORT
  775         evdev_free(sc->sc_evdev);
  776 #endif
  777 
  778         usbd_transfer_unsetup(sc->sc_xfer, UMS_N_TRANSFER);
  779 
  780         usb_callout_drain(&sc->sc_callout);
  781 
  782         mtx_destroy(&sc->sc_mtx);
  783 
  784         return (0);
  785 }
  786 
  787 static void
  788 ums_reset(struct ums_softc *sc)
  789 {
  790 
  791         /* reset all USB mouse parameters */
  792 
  793         if (sc->sc_buttons > MOUSE_MSC_MAXBUTTON)
  794                 sc->sc_hw.buttons = MOUSE_MSC_MAXBUTTON;
  795         else
  796                 sc->sc_hw.buttons = sc->sc_buttons;
  797 
  798         sc->sc_hw.iftype = MOUSE_IF_USB;
  799         sc->sc_hw.type = MOUSE_MOUSE;
  800         sc->sc_hw.model = MOUSE_MODEL_GENERIC;
  801         sc->sc_hw.hwid = 0;
  802 
  803         sc->sc_mode.protocol = MOUSE_PROTO_MSC;
  804         sc->sc_mode.rate = -1;
  805         sc->sc_mode.resolution = MOUSE_RES_UNKNOWN;
  806         sc->sc_mode.accelfactor = 0;
  807         sc->sc_mode.level = 0;
  808         sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
  809         sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
  810         sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
  811 
  812         /* reset status */
  813 
  814         sc->sc_status.flags = 0;
  815         sc->sc_status.button = 0;
  816         sc->sc_status.obutton = 0;
  817         sc->sc_status.dx = 0;
  818         sc->sc_status.dy = 0;
  819         sc->sc_status.dz = 0;
  820         /* sc->sc_status.dt = 0; */
  821 }
  822 
  823 static void
  824 ums_start_rx(struct ums_softc *sc)
  825 {
  826         int rate;
  827 
  828         /* Check if we should override the default polling interval */
  829         rate = sc->sc_pollrate;
  830         /* Range check rate */
  831         if (rate > 1000)
  832                 rate = 1000;
  833         /* Check for set rate */
  834         if ((rate > 0) && (sc->sc_xfer[UMS_INTR_DT] != NULL)) {
  835                 DPRINTF("Setting pollrate = %d\n", rate);
  836                 /* Stop current transfer, if any */
  837                 usbd_transfer_stop(sc->sc_xfer[UMS_INTR_DT]);
  838                 /* Set new interval */
  839                 usbd_xfer_set_interval(sc->sc_xfer[UMS_INTR_DT], 1000 / rate);
  840                 /* Only set pollrate once */
  841                 sc->sc_pollrate = 0;
  842         }
  843 
  844         usbd_transfer_start(sc->sc_xfer[UMS_INTR_DT]);
  845 }
  846 
  847 static void
  848 ums_stop_rx(struct ums_softc *sc)
  849 {
  850         usbd_transfer_stop(sc->sc_xfer[UMS_INTR_DT]);
  851         usb_callout_stop(&sc->sc_callout);
  852 }
  853 
  854 static void
  855 ums_fifo_start_read(struct usb_fifo *fifo)
  856 {
  857         struct ums_softc *sc = usb_fifo_softc(fifo);
  858 
  859         ums_start_rx(sc);
  860 }
  861 
  862 static void
  863 ums_fifo_stop_read(struct usb_fifo *fifo)
  864 {
  865         struct ums_softc *sc = usb_fifo_softc(fifo);
  866 
  867 #ifdef EVDEV_SUPPORT
  868         if ((sc->sc_evflags & UMS_EVDEV_OPENED) == 0)
  869 #endif
  870                 ums_stop_rx(sc);
  871 }
  872 
  873 #if ((MOUSE_SYS_PACKETSIZE != 8) || \
  874      (MOUSE_MSC_PACKETSIZE != 5))
  875 #error "Software assumptions are not met. Please update code."
  876 #endif
  877 
  878 static void
  879 ums_put_queue(struct ums_softc *sc, int32_t dx, int32_t dy,
  880     int32_t dz, int32_t dt, int32_t buttons)
  881 {
  882         uint8_t buf[8];
  883 
  884 #ifdef EVDEV_SUPPORT
  885         if (evdev_is_grabbed(sc->sc_evdev))
  886                 return;
  887 #endif
  888         if (1) {
  889                 if (dx > 254)
  890                         dx = 254;
  891                 if (dx < -256)
  892                         dx = -256;
  893                 if (dy > 254)
  894                         dy = 254;
  895                 if (dy < -256)
  896                         dy = -256;
  897                 if (dz > 126)
  898                         dz = 126;
  899                 if (dz < -128)
  900                         dz = -128;
  901                 if (dt > 126)
  902                         dt = 126;
  903                 if (dt < -128)
  904                         dt = -128;
  905 
  906                 buf[0] = sc->sc_mode.syncmask[1];
  907                 buf[0] |= (~buttons) & MOUSE_MSC_BUTTONS;
  908                 buf[1] = dx >> 1;
  909                 buf[2] = dy >> 1;
  910                 buf[3] = dx - (dx >> 1);
  911                 buf[4] = dy - (dy >> 1);
  912 
  913                 if (sc->sc_mode.level == 1) {
  914                         buf[5] = dz >> 1;
  915                         buf[6] = dz - (dz >> 1);
  916                         buf[7] = (((~buttons) >> 3) & MOUSE_SYS_EXTBUTTONS);
  917                 }
  918                 usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf,
  919                     sc->sc_mode.packetsize, 1);
  920         } else {
  921                 DPRINTF("Buffer full, discarded packet\n");
  922         }
  923 }
  924 
  925 #ifdef EVDEV_SUPPORT
  926 static void
  927 ums_evdev_push(struct ums_softc *sc, int32_t dx, int32_t dy,
  928     int32_t dz, int32_t dt, int32_t buttons)
  929 {
  930         if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) {
  931                 /* Push evdev event */
  932                 evdev_push_rel(sc->sc_evdev, REL_X, dx);
  933                 evdev_push_rel(sc->sc_evdev, REL_Y, -dy);
  934                 evdev_push_rel(sc->sc_evdev, REL_WHEEL, -dz);
  935                 evdev_push_rel(sc->sc_evdev, REL_HWHEEL, dt);
  936                 evdev_push_mouse_btn(sc->sc_evdev,
  937                     (buttons & ~MOUSE_STDBUTTONS) |
  938                     (buttons & (1 << 2) ? MOUSE_BUTTON1DOWN : 0) |
  939                     (buttons & (1 << 1) ? MOUSE_BUTTON2DOWN : 0) |
  940                     (buttons & (1 << 0) ? MOUSE_BUTTON3DOWN : 0));
  941                 evdev_sync(sc->sc_evdev);
  942         }
  943 }
  944 #endif
  945 
  946 static void
  947 ums_reset_buf(struct ums_softc *sc)
  948 {
  949         /* reset read queue, must be called locked */
  950         usb_fifo_reset(sc->sc_fifo.fp[USB_FIFO_RX]);
  951 }
  952 
  953 #ifdef EVDEV_SUPPORT
  954 static int
  955 ums_ev_open(struct evdev_dev *evdev)
  956 {
  957         struct ums_softc *sc = evdev_get_softc(evdev);
  958 
  959         mtx_assert(&sc->sc_mtx, MA_OWNED);
  960 
  961         sc->sc_evflags |= UMS_EVDEV_OPENED;
  962 
  963         if (sc->sc_fflags == 0) {
  964                 ums_reset(sc);
  965         }
  966         ums_start_rx(sc);
  967 
  968         return (0);
  969 }
  970 
  971 static int
  972 ums_ev_close(struct evdev_dev *evdev)
  973 {
  974         struct ums_softc *sc = evdev_get_softc(evdev);
  975 
  976         mtx_assert(&sc->sc_mtx, MA_OWNED);
  977 
  978         sc->sc_evflags &= ~UMS_EVDEV_OPENED;
  979 
  980         if (sc->sc_fflags == 0)
  981                 ums_stop_rx(sc);
  982 
  983         return (0);
  984 }
  985 #endif
  986 
  987 static int
  988 ums_fifo_open(struct usb_fifo *fifo, int fflags)
  989 {
  990         struct ums_softc *sc = usb_fifo_softc(fifo);
  991 
  992         DPRINTFN(2, "\n");
  993 
  994         /* check for duplicate open, should not happen */
  995         if (sc->sc_fflags & fflags)
  996                 return (EBUSY);
  997 
  998         /* check for first open */
  999 #ifdef EVDEV_SUPPORT
 1000         if (sc->sc_fflags == 0 && (sc->sc_evflags & UMS_EVDEV_OPENED) == 0)
 1001                 ums_reset(sc);
 1002 #else
 1003         if (sc->sc_fflags == 0)
 1004                 ums_reset(sc);
 1005 #endif
 1006 
 1007         if (fflags & FREAD) {
 1008                 /* allocate RX buffer */
 1009                 if (usb_fifo_alloc_buffer(fifo,
 1010                     UMS_BUF_SIZE, UMS_IFQ_MAXLEN)) {
 1011                         return (ENOMEM);
 1012                 }
 1013         }
 1014 
 1015         sc->sc_fflags |= fflags & (FREAD | FWRITE);
 1016         return (0);
 1017 }
 1018 
 1019 static void
 1020 ums_fifo_close(struct usb_fifo *fifo, int fflags)
 1021 {
 1022         struct ums_softc *sc = usb_fifo_softc(fifo);
 1023 
 1024         DPRINTFN(2, "\n");
 1025 
 1026         if (fflags & FREAD)
 1027                 usb_fifo_free_buffer(fifo);
 1028 
 1029         sc->sc_fflags &= ~(fflags & (FREAD | FWRITE));
 1030 }
 1031 
 1032 static int
 1033 ums_fifo_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags)
 1034 {
 1035         struct ums_softc *sc = usb_fifo_softc(fifo);
 1036         mousemode_t mode;
 1037         int error = 0;
 1038 
 1039         DPRINTFN(2, "\n");
 1040 
 1041         mtx_lock(&sc->sc_mtx);
 1042 
 1043         switch (cmd) {
 1044         case MOUSE_GETHWINFO:
 1045                 *(mousehw_t *)addr = sc->sc_hw;
 1046                 break;
 1047 
 1048         case MOUSE_GETMODE:
 1049                 *(mousemode_t *)addr = sc->sc_mode;
 1050                 break;
 1051 
 1052         case MOUSE_SETMODE:
 1053                 mode = *(mousemode_t *)addr;
 1054 
 1055                 if (mode.level == -1) {
 1056                         /* don't change the current setting */
 1057                 } else if ((mode.level < 0) || (mode.level > 1)) {
 1058                         error = EINVAL;
 1059                         break;
 1060                 } else {
 1061                         sc->sc_mode.level = mode.level;
 1062                 }
 1063 
 1064                 /* store polling rate */
 1065                 sc->sc_pollrate = mode.rate;
 1066 
 1067                 if (sc->sc_mode.level == 0) {
 1068                         if (sc->sc_buttons > MOUSE_MSC_MAXBUTTON)
 1069                                 sc->sc_hw.buttons = MOUSE_MSC_MAXBUTTON;
 1070                         else
 1071                                 sc->sc_hw.buttons = sc->sc_buttons;
 1072                         sc->sc_mode.protocol = MOUSE_PROTO_MSC;
 1073                         sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
 1074                         sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
 1075                         sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
 1076                 } else if (sc->sc_mode.level == 1) {
 1077                         if (sc->sc_buttons > MOUSE_SYS_MAXBUTTON)
 1078                                 sc->sc_hw.buttons = MOUSE_SYS_MAXBUTTON;
 1079                         else
 1080                                 sc->sc_hw.buttons = sc->sc_buttons;
 1081                         sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE;
 1082                         sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE;
 1083                         sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
 1084                         sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC;
 1085                 }
 1086                 ums_reset_buf(sc);
 1087                 break;
 1088 
 1089         case MOUSE_GETLEVEL:
 1090                 *(int *)addr = sc->sc_mode.level;
 1091                 break;
 1092 
 1093         case MOUSE_SETLEVEL:
 1094                 if (*(int *)addr < 0 || *(int *)addr > 1) {
 1095                         error = EINVAL;
 1096                         break;
 1097                 }
 1098                 sc->sc_mode.level = *(int *)addr;
 1099 
 1100                 if (sc->sc_mode.level == 0) {
 1101                         if (sc->sc_buttons > MOUSE_MSC_MAXBUTTON)
 1102                                 sc->sc_hw.buttons = MOUSE_MSC_MAXBUTTON;
 1103                         else
 1104                                 sc->sc_hw.buttons = sc->sc_buttons;
 1105                         sc->sc_mode.protocol = MOUSE_PROTO_MSC;
 1106                         sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
 1107                         sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
 1108                         sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
 1109                 } else if (sc->sc_mode.level == 1) {
 1110                         if (sc->sc_buttons > MOUSE_SYS_MAXBUTTON)
 1111                                 sc->sc_hw.buttons = MOUSE_SYS_MAXBUTTON;
 1112                         else
 1113                                 sc->sc_hw.buttons = sc->sc_buttons;
 1114                         sc->sc_mode.protocol = MOUSE_PROTO_SYSMOUSE;
 1115                         sc->sc_mode.packetsize = MOUSE_SYS_PACKETSIZE;
 1116                         sc->sc_mode.syncmask[0] = MOUSE_SYS_SYNCMASK;
 1117                         sc->sc_mode.syncmask[1] = MOUSE_SYS_SYNC;
 1118                 }
 1119                 ums_reset_buf(sc);
 1120                 break;
 1121 
 1122         case MOUSE_GETSTATUS:{
 1123                         mousestatus_t *status = (mousestatus_t *)addr;
 1124 
 1125                         *status = sc->sc_status;
 1126                         sc->sc_status.obutton = sc->sc_status.button;
 1127                         sc->sc_status.button = 0;
 1128                         sc->sc_status.dx = 0;
 1129                         sc->sc_status.dy = 0;
 1130                         sc->sc_status.dz = 0;
 1131                         /* sc->sc_status.dt = 0; */
 1132 
 1133                         if (status->dx || status->dy || status->dz /* || status->dt */ ) {
 1134                                 status->flags |= MOUSE_POSCHANGED;
 1135                         }
 1136                         if (status->button != status->obutton) {
 1137                                 status->flags |= MOUSE_BUTTONSCHANGED;
 1138                         }
 1139                         break;
 1140                 }
 1141         default:
 1142                 error = ENOTTY;
 1143                 break;
 1144         }
 1145 
 1146         mtx_unlock(&sc->sc_mtx);
 1147         return (error);
 1148 }
 1149 
 1150 static int
 1151 ums_sysctl_handler_parseinfo(SYSCTL_HANDLER_ARGS)
 1152 {
 1153         struct ums_softc *sc = arg1;
 1154         struct ums_info *info;
 1155         struct sbuf *sb;
 1156         int i, j, err, had_output;
 1157 
 1158         sb = sbuf_new_auto();
 1159         for (i = 0, had_output = 0; i < UMS_INFO_MAX; i++) {
 1160                 info = &sc->sc_info[i];
 1161 
 1162                 /* Don't emit empty info */
 1163                 if ((info->sc_flags &
 1164                     (UMS_FLAG_X_AXIS | UMS_FLAG_Y_AXIS | UMS_FLAG_Z_AXIS |
 1165                      UMS_FLAG_T_AXIS | UMS_FLAG_W_AXIS)) == 0 &&
 1166                     info->sc_buttons == 0)
 1167                         continue;
 1168 
 1169                 if (had_output)
 1170                         sbuf_printf(sb, "\n");
 1171                 had_output = 1;
 1172                 sbuf_printf(sb, "i%d:", i + 1);
 1173                 if (info->sc_flags & UMS_FLAG_X_AXIS)
 1174                         sbuf_printf(sb, " X:r%d, p%d, s%d;",
 1175                             (int)info->sc_iid_x,
 1176                             (int)info->sc_loc_x.pos,
 1177                             (int)info->sc_loc_x.size);
 1178                 if (info->sc_flags & UMS_FLAG_Y_AXIS)
 1179                         sbuf_printf(sb, " Y:r%d, p%d, s%d;",
 1180                             (int)info->sc_iid_y,
 1181                             (int)info->sc_loc_y.pos,
 1182                             (int)info->sc_loc_y.size);
 1183                 if (info->sc_flags & UMS_FLAG_Z_AXIS)
 1184                         sbuf_printf(sb, " Z:r%d, p%d, s%d;",
 1185                             (int)info->sc_iid_z,
 1186                             (int)info->sc_loc_z.pos,
 1187                             (int)info->sc_loc_z.size);
 1188                 if (info->sc_flags & UMS_FLAG_T_AXIS)
 1189                         sbuf_printf(sb, " T:r%d, p%d, s%d;",
 1190                             (int)info->sc_iid_t,
 1191                             (int)info->sc_loc_t.pos,
 1192                             (int)info->sc_loc_t.size);
 1193                 if (info->sc_flags & UMS_FLAG_W_AXIS)
 1194                         sbuf_printf(sb, " W:r%d, p%d, s%d;",
 1195                             (int)info->sc_iid_w,
 1196                             (int)info->sc_loc_w.pos,
 1197                             (int)info->sc_loc_w.size);
 1198 
 1199                 for (j = 0; j < info->sc_buttons; j++) {
 1200                         sbuf_printf(sb, " B%d:r%d, p%d, s%d;", j + 1,
 1201                             (int)info->sc_iid_btn[j],
 1202                             (int)info->sc_loc_btn[j].pos,
 1203                             (int)info->sc_loc_btn[j].size);
 1204                 }
 1205         }
 1206         sbuf_finish(sb);
 1207         err = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
 1208         sbuf_delete(sb);
 1209 
 1210         return (err);
 1211 }
 1212 
 1213 static device_method_t ums_methods[] = {
 1214         DEVMETHOD(device_probe, ums_probe),
 1215         DEVMETHOD(device_attach, ums_attach),
 1216         DEVMETHOD(device_detach, ums_detach),
 1217 
 1218         DEVMETHOD_END
 1219 };
 1220 
 1221 static driver_t ums_driver = {
 1222         .name = "ums",
 1223         .methods = ums_methods,
 1224         .size = sizeof(struct ums_softc),
 1225 };
 1226 
 1227 DRIVER_MODULE(ums, uhub, ums_driver, NULL, NULL);
 1228 MODULE_DEPEND(ums, usb, 1, 1, 1);
 1229 MODULE_DEPEND(ums, hid, 1, 1, 1);
 1230 #ifdef EVDEV_SUPPORT
 1231 MODULE_DEPEND(ums, evdev, 1, 1, 1);
 1232 #endif
 1233 MODULE_VERSION(ums, 1);
 1234 USB_PNP_HOST_INFO(ums_devs);

Cache object: cbabc9656df05408c6ef9d17a57ebca0


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