root/dev/bluetooth/btms.c

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

DEFINITIONS

This source file includes following definitions.
  1. btms_match
  2. btms_attach
  3. btms_detach
  4. btms_enable
  5. btms_ioctl
  6. btms_disable
  7. btms_input

    1 /*      $OpenBSD: btms.c,v 1.1 2007/07/27 16:52:24 gwk Exp $    */
    2 /*      $NetBSD: btms.c,v 1.6 2007/03/04 06:01:45 christos Exp $        */
    3 
    4 /*-
    5  * Copyright (c) 2006 Itronix Inc.
    6  * All rights reserved.
    7  *
    8  * Written by Iain Hibbert for Itronix Inc.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. The name of Itronix Inc. may not be used to endorse
   19  *    or promote products derived from this software without specific
   20  *    prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
   26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   27  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   29  * ON ANY THEORY OF LIABILITY, WHETHER IN
   30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32  * POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 
   35 /*
   36  * based on dev/usb/ums.c
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/conf.h>
   41 #include <sys/device.h>
   42 #include <sys/proc.h>
   43 #include <sys/systm.h>
   44 
   45 #include <netbt/bluetooth.h>
   46 
   47 #include <dev/bluetooth/bthid.h>
   48 #include <dev/bluetooth/bthidev.h>
   49 
   50 #include <dev/usb/hid.h>
   51 #include <dev/usb/usb.h>
   52 #include <dev/usb/usbhid.h>
   53 
   54 #include <dev/wscons/wsconsio.h>
   55 #include <dev/wscons/wsmousevar.h>
   56 
   57 #define MAX_BUTTONS     31
   58 #define BUTTON(n)       (1 << (((n) == 1 || (n) == 2) ? 3 - (n) : (n)))
   59 #define NOTMOUSE(f)     (((f) & (HIO_CONST | HIO_RELATIVE)) != HIO_RELATIVE)
   60 
   61 struct btms_softc {
   62         struct bthidev           sc_hidev;      /* device+ */
   63 
   64         struct device           *sc_wsmouse;    /* child */
   65         int                      sc_enabled;
   66         uint16_t                 sc_flags;
   67 
   68         /* locators */
   69         struct hid_location      sc_loc_x;
   70         struct hid_location      sc_loc_y;
   71         struct hid_location      sc_loc_z;
   72         struct hid_location      sc_loc_w;
   73         struct hid_location      sc_loc_button[MAX_BUTTONS];
   74 
   75         int                      sc_num_buttons;
   76         uint32_t                 sc_buttons;
   77 };
   78 
   79 /* sc_flags */
   80 #define BTMS_REVZ               (1 << 0)        /* reverse Z direction */
   81 #define BTMS_HASZ               (1 << 1)        /* has Z direction */
   82 #define BTMS_HASW               (1 << 2)        /* has W direction */
   83 
   84 int     btms_match(struct device *, struct cfdata *, void *);
   85 void    btms_attach(struct device *, struct device *, void *);
   86 int     btms_detach(struct device *, int);
   87 
   88 struct cfdriver btms_cd = {
   89         NULL, "btms", DV_DULL
   90 };
   91 
   92 const struct cfattach btms_ca = {
   93         sizeof(struct btms_softc),
   94         btms_match,
   95         btms_attach,
   96         btms_detach,
   97 };
   98 
   99 /* wsmouse(4) accessops */
  100 int     btms_enable(void *);
  101 int     btms_ioctl(void *, unsigned long, void *, int, struct lwp *);
  102 void    btms_disable(void *);
  103 
  104 const struct wsmouse_accessops btms_accessops = {
  105         btms_enable,
  106         btms_ioctl,
  107         btms_disable,
  108 };
  109 
  110 /* bthid methods */
  111 void btms_input(struct bthidev *, uint8_t *, int);
  112 
  113 
  114 int
  115 btms_match(struct device *parent, struct cfdata *match, void *aux)
  116 {
  117         struct bthidev_attach_args *ba = aux;
  118 
  119         if (hid_is_collection(ba->ba_desc, ba->ba_dlen, ba->ba_id,
  120             HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)))
  121                 return 1;
  122 
  123         return 0;
  124 }
  125 
  126 void
  127 btms_attach(struct device *parent, struct device *self, void *aux)
  128 {
  129         struct btms_softc *sc = (struct btms_softc *)self;
  130         struct bthidev_attach_args *ba = aux;
  131         struct wsmousedev_attach_args wsma;
  132         struct hid_location *zloc;
  133         uint32_t flags;
  134         int i, hl;
  135 
  136         ba->ba_input = btms_input;
  137 
  138         /* control the horizontal */
  139         hl = hid_locate(ba->ba_desc, ba->ba_dlen,
  140             HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), ba->ba_id, hid_input,
  141             &sc->sc_loc_x, &flags);
  142 
  143         if (hl == 0 || NOTMOUSE(flags)) {
  144                 printf("\n%s: X report 0x%04x not supported\n",
  145                     sc->sc_hidev.sc_dev.dv_xname, flags);
  146 
  147                 return;
  148         }
  149 
  150         /* control the vertical */
  151         hl = hid_locate(ba->ba_desc, ba->ba_dlen,
  152             HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), ba->ba_id, hid_input,
  153             &sc->sc_loc_y, &flags);
  154 
  155         if (hl == 0 || NOTMOUSE(flags)) {
  156                 printf("\n%s: Y report 0x%04x not supported\n",
  157                     sc->sc_hidev.sc_dev.dv_xname, flags);
  158 
  159                 return;
  160         }
  161 
  162         /* Try the wheel first as the Z activator since it's tradition. */
  163         hl = hid_locate(ba->ba_desc, ba->ba_dlen,
  164             HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL), ba->ba_id, hid_input,
  165             &sc->sc_loc_z, &flags);
  166 
  167         zloc = &sc->sc_loc_z;
  168         if (hl) {
  169                 if (NOTMOUSE(flags)) {
  170                         printf("\n%s: Wheel report 0x%04x not supported\n",
  171                             sc->sc_hidev.sc_dev.dv_xname, flags);
  172 
  173                         /* ignore Bad Z coord */
  174                         sc->sc_loc_z.size = 0;
  175                 } else {
  176                         sc->sc_flags |= BTMS_HASZ;
  177                         /* Wheels need the Z axis reversed. */
  178                         sc->sc_flags ^= BTMS_REVZ;
  179                         /* Put Z on the W coordinate */
  180                         zloc = &sc->sc_loc_w;
  181                 }
  182         }
  183 
  184         hl = hid_locate(ba->ba_desc, ba->ba_dlen,
  185             HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), ba->ba_id, hid_input,
  186             zloc, &flags);
  187 
  188         /*
  189          * The horizontal component of the scrollball can also be given by
  190          * Application Control Pan in the Consumer page, so if we didnt see
  191          * any Z then check that.
  192          */
  193         if (!hl) {
  194                 hl = hid_locate(ba->ba_desc, ba->ba_dlen,
  195                     HID_USAGE2(HUP_CONSUMER, HUC_AC_PAN), ba->ba_id, hid_input,
  196                     zloc, &flags);
  197         }
  198 
  199         if (hl) {
  200                 if (NOTMOUSE(flags))
  201                         zloc->size = 0; /* ignore Z */
  202                 else {
  203                         if (sc->sc_flags & BTMS_HASZ)
  204                                 sc->sc_flags |= BTMS_HASW;
  205                         else
  206                                 sc->sc_flags |= BTMS_HASZ;
  207                 }
  208         }
  209 
  210         for (i = 1 ; i <= MAX_BUTTONS ; i++) {
  211                 hl = hid_locate(ba->ba_desc, ba->ba_dlen,
  212                     HID_USAGE2(HUP_BUTTON, i), ba->ba_id, hid_input,
  213                     &sc->sc_loc_button[i - 1], NULL);
  214 
  215                 if (hl == 0)
  216                         break;
  217         }
  218         sc->sc_num_buttons = i - 1;
  219 
  220         printf(": %d button%s%s%s%s.\n", sc->sc_num_buttons,
  221             sc->sc_num_buttons == 1 ? "" : "s",
  222             sc->sc_flags & BTMS_HASW ? ", W" : "",
  223             sc->sc_flags & BTMS_HASZ ? " and Z dir" : "",
  224             sc->sc_flags & BTMS_HASW ? "s" : "");
  225 
  226         wsma.accessops = &btms_accessops;
  227         wsma.accesscookie = sc;
  228 
  229         sc->sc_wsmouse = config_found((struct device *)sc,
  230             &wsma, wsmousedevprint);
  231 }
  232 
  233 int
  234 btms_detach(struct device *self, int flags)
  235 {
  236         struct btms_softc *sc = (struct btms_softc *)self;
  237         int err = 0;
  238 
  239         if (sc->sc_wsmouse != NULL) {
  240                 err = config_detach(sc->sc_wsmouse, flags);
  241                 sc->sc_wsmouse = NULL;
  242         }
  243 
  244         return err;
  245 }
  246 
  247 int
  248 btms_enable(void *self)
  249 {
  250         struct btms_softc *sc = (struct btms_softc *)self;
  251 
  252         if (sc->sc_enabled)
  253                 return EBUSY;
  254 
  255         sc->sc_enabled = 1;
  256         return 0;
  257 }
  258 
  259 int
  260 btms_ioctl(void *self, unsigned long cmd, void *data, int flag, struct lwp *l)
  261 {
  262         /* struct btms_softc *sc = (struct btms_softc *)self; */
  263 
  264         switch (cmd) {
  265         case WSMOUSEIO_GTYPE:
  266                 *(uint *)data = WSMOUSE_TYPE_BLUETOOTH;
  267                 break;
  268 
  269         default:
  270                 return EPASSTHROUGH;
  271         }
  272 
  273         return 0;
  274 }
  275 
  276 void
  277 btms_disable(void *self)
  278 {
  279         struct btms_softc *sc = (struct btms_softc *)self;
  280 
  281         sc->sc_enabled = 0;
  282 }
  283 
  284 void
  285 btms_input(struct bthidev *self, uint8_t *data, int len)
  286 {
  287         struct btms_softc *sc = (struct btms_softc *)self;
  288         int dx, dy, dz, dw;
  289         uint32_t buttons;
  290         int i, s;
  291 
  292         if (sc->sc_wsmouse == NULL || sc->sc_enabled == 0)
  293                 return;
  294 
  295         dx =  hid_get_data(data, &sc->sc_loc_x);
  296         dy = -hid_get_data(data, &sc->sc_loc_y);
  297         dz =  hid_get_data(data, &sc->sc_loc_z);
  298         dw =  hid_get_data(data, &sc->sc_loc_w);
  299 
  300         if (sc->sc_flags & BTMS_REVZ)
  301                 dz = -dz;
  302 
  303         buttons = 0;
  304         for (i = 0 ; i < sc->sc_num_buttons ; i++)
  305                 if (hid_get_data(data, &sc->sc_loc_button[i]))
  306                         buttons |= BUTTON(i);
  307 
  308         if (dx != 0 || dy != 0 || dz != 0 || dw != 0 ||
  309             buttons != sc->sc_buttons) {
  310                 sc->sc_buttons = buttons;
  311 
  312                 s = spltty();
  313                 wsmouse_input(sc->sc_wsmouse, buttons, dx, dy, dz, dw,
  314                     WSMOUSE_INPUT_DELTA);
  315                 splx(s);
  316         }
  317 }

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