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/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 /*      $NetBSD: ums.c,v 1.60 2003/03/11 16:44:00 augustss Exp $        */
    2 
    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  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *        This product includes software developed by the NetBSD
   22  *        Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
   42  */
   43 
   44 #include <sys/cdefs.h>
   45 __KERNEL_RCSID(0, "$NetBSD: ums.c,v 1.60 2003/03/11 16:44:00 augustss Exp $");
   46 
   47 #include <sys/param.h>
   48 #include <sys/systm.h>
   49 #include <sys/kernel.h>
   50 #include <sys/malloc.h>
   51 #include <sys/device.h>
   52 #include <sys/ioctl.h>
   53 #include <sys/tty.h>
   54 #include <sys/file.h>
   55 #include <sys/select.h>
   56 #include <sys/proc.h>
   57 #include <sys/vnode.h>
   58 #include <sys/poll.h>
   59 
   60 #include <dev/usb/usb.h>
   61 #include <dev/usb/usbhid.h>
   62 
   63 #include <dev/usb/usbdi.h>
   64 #include <dev/usb/usbdi_util.h>
   65 #include <dev/usb/usbdevs.h>
   66 #include <dev/usb/usb_quirks.h>
   67 #include <dev/usb/uhidev.h>
   68 #include <dev/usb/hid.h>
   69 
   70 #include <dev/wscons/wsconsio.h>
   71 #include <dev/wscons/wsmousevar.h>
   72 
   73 #ifdef USB_DEBUG
   74 #define DPRINTF(x)      if (umsdebug) logprintf x
   75 #define DPRINTFN(n,x)   if (umsdebug>(n)) logprintf x
   76 int     umsdebug = 0;
   77 #else
   78 #define DPRINTF(x)
   79 #define DPRINTFN(n,x)
   80 #endif
   81 
   82 #define UMS_BUT(i) ((i) == 1 || (i) == 2 ? 3 - (i) : i)
   83 
   84 #define UMSUNIT(s)      (minor(s))
   85 
   86 #define PS2LBUTMASK     x01
   87 #define PS2RBUTMASK     x02
   88 #define PS2MBUTMASK     x04
   89 #define PS2BUTMASK 0x0f
   90 
   91 #define MAX_BUTTONS     7       /* must not exceed size of sc_buttons */
   92 
   93 struct ums_softc {
   94         struct uhidev sc_hdev;
   95 
   96         struct hid_location sc_loc_x, sc_loc_y, sc_loc_z;
   97         struct hid_location sc_loc_btn[MAX_BUTTONS];
   98 
   99         int sc_enabled;
  100 
  101         int flags;              /* device configuration */
  102 #define UMS_Z           0x01    /* z direction available */
  103 #define UMS_SPUR_BUT_UP 0x02    /* spurious button up events */
  104 #define UMS_REVZ        0x04    /* Z-axis is reversed */
  105 
  106         int nbuttons;
  107 
  108         u_int32_t sc_buttons;   /* mouse button status */
  109         struct device *sc_wsmousedev;
  110 
  111         char                    sc_dying;
  112 };
  113 
  114 #define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE)
  115 #define MOUSE_FLAGS (HIO_RELATIVE)
  116 
  117 Static void ums_intr(struct uhidev *addr, void *ibuf, u_int len);
  118 
  119 Static int      ums_enable(void *);
  120 Static void     ums_disable(void *);
  121 Static int      ums_ioctl(void *, u_long, caddr_t, int, usb_proc_ptr );
  122 
  123 const struct wsmouse_accessops ums_accessops = {
  124         ums_enable,
  125         ums_ioctl,
  126         ums_disable,
  127 };
  128 
  129 USB_DECLARE_DRIVER(ums);
  130 
  131 int
  132 ums_match(struct device *parent, struct cfdata *match, void *aux)
  133 {
  134         struct uhidev_attach_arg *uha = aux;
  135         int size;
  136         void *desc;
  137 
  138         uhidev_get_report_desc(uha->parent, &desc, &size);
  139         if (!hid_is_collection(desc, size, uha->reportid,
  140                                HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)))
  141                 return (UMATCH_NONE);
  142 
  143         return (UMATCH_IFACECLASS);
  144 }
  145 
  146 void
  147 ums_attach(struct device *parent, struct device *self, void *aux)
  148 {
  149         struct ums_softc *sc = (struct ums_softc *)self;
  150         struct uhidev_attach_arg *uha = aux;
  151         struct wsmousedev_attach_args a;
  152         int size;
  153         void *desc;
  154         u_int32_t flags, quirks;
  155         int i, wheel;
  156         struct hid_location loc_btn;
  157 
  158         sc->sc_hdev.sc_intr = ums_intr;
  159         sc->sc_hdev.sc_parent = uha->parent;
  160         sc->sc_hdev.sc_report_id = uha->reportid;
  161 
  162         quirks = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
  163         if (quirks & UQ_MS_REVZ)
  164                 sc->flags |= UMS_REVZ;
  165         if (quirks & UQ_SPUR_BUT_UP)
  166                 sc->flags |= UMS_SPUR_BUT_UP;
  167 
  168         uhidev_get_report_desc(uha->parent, &desc, &size);
  169 
  170         if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
  171                uha->reportid, hid_input, &sc->sc_loc_x, &flags)) {
  172                 printf("\n%s: mouse has no X report\n",
  173                        USBDEVNAME(sc->sc_hdev.sc_dev));
  174                 USB_ATTACH_ERROR_RETURN;
  175         }
  176         if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
  177                 printf("\n%s: X report 0x%04x not supported\n",
  178                        USBDEVNAME(sc->sc_hdev.sc_dev), flags);
  179                 USB_ATTACH_ERROR_RETURN;
  180         }
  181 
  182         if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
  183                uha->reportid, hid_input, &sc->sc_loc_y, &flags)) {
  184                 printf("\n%s: mouse has no Y report\n",
  185                        USBDEVNAME(sc->sc_hdev.sc_dev));
  186                 USB_ATTACH_ERROR_RETURN;
  187         }
  188         if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
  189                 printf("\n%s: Y report 0x%04x not supported\n",
  190                        USBDEVNAME(sc->sc_hdev.sc_dev), flags);
  191                 USB_ATTACH_ERROR_RETURN;
  192         }
  193 
  194         /* Try to guess the Z activator: first check Z, then WHEEL. */
  195         wheel = 0;
  196         if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z),
  197                uha->reportid, hid_input, &sc->sc_loc_z, &flags) ||
  198             (wheel = hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP,
  199                                                        HUG_WHEEL),
  200                uha->reportid, hid_input, &sc->sc_loc_z, &flags))) {
  201                 if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) {
  202                         sc->sc_loc_z.size = 0;  /* Bad Z coord, ignore it */
  203                 } else {
  204                         sc->flags |= UMS_Z;
  205                         /* Wheels need the Z axis reversed. */
  206                         if (wheel)
  207                                 sc->flags ^= UMS_REVZ;
  208                 }
  209         }
  210 
  211         /* figure out the number of buttons */
  212         for (i = 1; i <= MAX_BUTTONS; i++)
  213                 if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
  214                         uha->reportid, hid_input, &loc_btn, 0))
  215                         break;
  216         sc->nbuttons = i - 1;
  217 
  218         printf(": %d button%s%s\n",
  219             sc->nbuttons, sc->nbuttons == 1 ? "" : "s",
  220             sc->flags & UMS_Z ? " and Z dir." : "");
  221 
  222         for (i = 1; i <= sc->nbuttons; i++)
  223                 hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i),
  224                            uha->reportid, hid_input,
  225                            &sc->sc_loc_btn[i-1], 0);
  226 
  227 #ifdef USB_DEBUG
  228         DPRINTF(("ums_attach: sc=%p\n", sc));
  229         DPRINTF(("ums_attach: X\t%d/%d\n",
  230                  sc->sc_loc_x.pos, sc->sc_loc_x.size));
  231         DPRINTF(("ums_attach: Y\t%d/%d\n",
  232                  sc->sc_loc_y.pos, sc->sc_loc_y.size));
  233         if (sc->flags & UMS_Z)
  234                 DPRINTF(("ums_attach: Z\t%d/%d\n",
  235                          sc->sc_loc_z.pos, sc->sc_loc_z.size));
  236         for (i = 1; i <= sc->nbuttons; i++) {
  237                 DPRINTF(("ums_attach: B%d\t%d/%d\n",
  238                          i, sc->sc_loc_btn[i-1].pos,sc->sc_loc_btn[i-1].size));
  239         }
  240 #endif
  241 
  242         a.accessops = &ums_accessops;
  243         a.accesscookie = sc;
  244 
  245         sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
  246 
  247         USB_ATTACH_SUCCESS_RETURN;
  248 }
  249 
  250 int
  251 ums_activate(device_ptr_t self, enum devact act)
  252 {
  253         struct ums_softc *sc = (struct ums_softc *)self;
  254         int rv = 0;
  255 
  256         switch (act) {
  257         case DVACT_ACTIVATE:
  258                 return (EOPNOTSUPP);
  259 
  260         case DVACT_DEACTIVATE:
  261                 if (sc->sc_wsmousedev != NULL)
  262                         rv = config_deactivate(sc->sc_wsmousedev);
  263                 sc->sc_dying = 1;
  264                 break;
  265         }
  266         return (rv);
  267 }
  268 
  269 int
  270 ums_detach(struct device *self, int flags)
  271 {
  272         struct ums_softc *sc = (struct ums_softc *)self;
  273         int rv = 0;
  274 
  275         DPRINTF(("ums_detach: sc=%p flags=%d\n", sc, flags));
  276 
  277         /* No need to do reference counting of ums, wsmouse has all the goo. */
  278         if (sc->sc_wsmousedev != NULL)
  279                 rv = config_detach(sc->sc_wsmousedev, flags);
  280 
  281         return (rv);
  282 }
  283 
  284 void
  285 ums_intr(struct uhidev *addr, void *ibuf, u_int len)
  286 {
  287         struct ums_softc *sc = (struct ums_softc *)addr;
  288         int dx, dy, dz;
  289         u_int32_t buttons = 0;
  290         int i;
  291         int s;
  292 
  293         DPRINTFN(5,("ums_intr: len=%d\n", len));
  294 
  295         dx =  hid_get_data(ibuf, &sc->sc_loc_x);
  296         dy = -hid_get_data(ibuf, &sc->sc_loc_y);
  297         dz =  hid_get_data(ibuf, &sc->sc_loc_z);
  298         if (sc->flags & UMS_REVZ)
  299                 dz = -dz;
  300         for (i = 0; i < sc->nbuttons; i++)
  301                 if (hid_get_data(ibuf, &sc->sc_loc_btn[i]))
  302                         buttons |= (1 << UMS_BUT(i));
  303 
  304         if (dx != 0 || dy != 0 || dz != 0 || buttons != sc->sc_buttons) {
  305                 DPRINTFN(10, ("ums_intr: x:%d y:%d z:%d buttons:0x%x\n",
  306                         dx, dy, dz, buttons));
  307                 sc->sc_buttons = buttons;
  308                 if (sc->sc_wsmousedev != NULL) {
  309                         s = spltty();
  310                         wsmouse_input(sc->sc_wsmousedev, buttons, dx, dy, dz,
  311                                       WSMOUSE_INPUT_DELTA);
  312                         splx(s);
  313                 }
  314         }
  315 }
  316 
  317 Static int
  318 ums_enable(void *v)
  319 {
  320         struct ums_softc *sc = v;
  321 
  322         DPRINTFN(1,("ums_enable: sc=%p\n", sc));
  323 
  324         if (sc->sc_dying)
  325                 return (EIO);
  326 
  327         if (sc->sc_enabled)
  328                 return (EBUSY);
  329 
  330         sc->sc_enabled = 1;
  331         sc->sc_buttons = 0;
  332 
  333         return (uhidev_open(&sc->sc_hdev));
  334 }
  335 
  336 Static void
  337 ums_disable(void *v)
  338 {
  339         struct ums_softc *sc = v;
  340 
  341         DPRINTFN(1,("ums_disable: sc=%p\n", sc));
  342 #ifdef DIAGNOSTIC
  343         if (!sc->sc_enabled) {
  344                 printf("ums_disable: not enabled\n");
  345                 return;
  346         }
  347 #endif
  348 
  349         sc->sc_enabled = 0;
  350         uhidev_close(&sc->sc_hdev);
  351 }
  352 
  353 Static int
  354 ums_ioctl(void *v, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
  355 
  356 {
  357         switch (cmd) {
  358         case WSMOUSEIO_GTYPE:
  359                 *(u_int *)data = WSMOUSE_TYPE_USB;
  360                 return (0);
  361         }
  362 
  363         return (EPASSTHROUGH);
  364 }

Cache object: d0b57468b39bddc352acb12267f959b5


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