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/hid/hpen.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) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
    5  * Copyright (c) 2019 Greg V <greg@unrelenting.technology>
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 /*
   33  * Generic / MS Windows compatible HID pen tablet driver:
   34  * https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/required-hid-top-level-collections
   35  *
   36  * Tested on: Wacom WCOM50C1 (Google Pixelbook "eve")
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/bus.h>
   41 #include <sys/kernel.h>
   42 #include <sys/malloc.h>
   43 #include <sys/module.h>
   44 #include <sys/sysctl.h>
   45 
   46 #include <dev/evdev/input.h>
   47 #include <dev/evdev/evdev.h>
   48 
   49 #include <dev/hid/hid.h>
   50 #include <dev/hid/hidbus.h>
   51 #include <dev/hid/hidmap.h>
   52 #include <dev/hid/hidrdesc.h>
   53 
   54 #include "usbdevs.h"
   55 
   56 static const uint8_t    hpen_graphire_report_descr[] =
   57                            { HID_GRAPHIRE_REPORT_DESCR() };
   58 static const uint8_t    hpen_graphire3_4x5_report_descr[] =
   59                            { HID_GRAPHIRE3_4X5_REPORT_DESCR() };
   60 
   61 static hidmap_cb_t      hpen_battery_strenght_cb;
   62 static hidmap_cb_t      hpen_final_digi_cb;
   63 static hidmap_cb_t      hpen_final_pen_cb;
   64 
   65 #define HPEN_MAP_BUT(usage, code)       \
   66         HIDMAP_KEY(HUP_DIGITIZERS, HUD_##usage, code)
   67 #define HPEN_MAP_ABS(usage, code)       \
   68         HIDMAP_ABS(HUP_DIGITIZERS, HUD_##usage, code)
   69 #define HPEN_MAP_ABS_GD(usage, code)    \
   70         HIDMAP_ABS(HUP_GENERIC_DESKTOP, HUG_##usage, code)
   71 #define HPEN_MAP_ABS_CB(usage, cb)      \
   72         HIDMAP_ABS_CB(HUP_DIGITIZERS, HUD_##usage, &cb)
   73 
   74 /* Generic map digitizer page map according to hut1_12v2.pdf */
   75 static const struct hidmap_item hpen_map_digi[] = {
   76     { HPEN_MAP_ABS_GD(X,                ABS_X),           .required = true },
   77     { HPEN_MAP_ABS_GD(Y,                ABS_Y),           .required = true },
   78     { HPEN_MAP_ABS(   TIP_PRESSURE,     ABS_PRESSURE) },
   79     { HPEN_MAP_ABS(   X_TILT,           ABS_TILT_X) },
   80     { HPEN_MAP_ABS(   Y_TILT,           ABS_TILT_Y) },
   81     { HPEN_MAP_ABS_CB(BATTERY_STRENGTH, hpen_battery_strenght_cb) },
   82     { HPEN_MAP_BUT(   TOUCH,            BTN_TOUCH) },
   83     { HPEN_MAP_BUT(   TIP_SWITCH,       BTN_TOUCH) },
   84     { HPEN_MAP_BUT(   SEC_TIP_SWITCH,   BTN_TOUCH) },
   85     { HPEN_MAP_BUT(   IN_RANGE,         BTN_TOOL_PEN) },
   86     { HPEN_MAP_BUT(   BARREL_SWITCH,    BTN_STYLUS) },
   87     { HPEN_MAP_BUT(   INVERT,           BTN_TOOL_RUBBER) },
   88     { HPEN_MAP_BUT(   ERASER,           BTN_TOUCH) },
   89     { HPEN_MAP_BUT(   TABLET_PICK,      BTN_STYLUS2) },
   90     { HPEN_MAP_BUT(   SEC_BARREL_SWITCH,BTN_STYLUS2) },
   91     { HIDMAP_FINAL_CB(                  &hpen_final_digi_cb) },
   92 };
   93 
   94 /* Microsoft-standardized pen support */
   95 static const struct hidmap_item hpen_map_pen[] = {
   96     { HPEN_MAP_ABS_GD(X,                ABS_X),           .required = true },
   97     { HPEN_MAP_ABS_GD(Y,                ABS_Y),           .required = true },
   98     { HPEN_MAP_ABS(   TIP_PRESSURE,     ABS_PRESSURE),    .required = true },
   99     { HPEN_MAP_ABS(   X_TILT,           ABS_TILT_X) },
  100     { HPEN_MAP_ABS(   Y_TILT,           ABS_TILT_Y) },
  101     { HPEN_MAP_ABS_CB(BATTERY_STRENGTH, hpen_battery_strenght_cb) },
  102     { HPEN_MAP_BUT(   TIP_SWITCH,       BTN_TOUCH),       .required = true },
  103     { HPEN_MAP_BUT(   IN_RANGE,         BTN_TOOL_PEN),    .required = true },
  104     { HPEN_MAP_BUT(   BARREL_SWITCH,    BTN_STYLUS) },
  105     { HPEN_MAP_BUT(   INVERT,           BTN_TOOL_RUBBER), .required = true },
  106     { HPEN_MAP_BUT(   ERASER,           BTN_TOUCH),       .required = true },
  107     { HIDMAP_FINAL_CB(                  &hpen_final_pen_cb) },
  108 };
  109 
  110 static const struct hid_device_id hpen_devs[] = {
  111         { HID_TLC(HUP_DIGITIZERS, HUD_DIGITIZER) },
  112         { HID_TLC(HUP_DIGITIZERS, HUD_PEN) },
  113 };
  114 
  115 static int
  116 hpen_battery_strenght_cb(HIDMAP_CB_ARGS)
  117 {
  118         struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV();
  119         int32_t data;
  120 
  121         switch (HIDMAP_CB_GET_STATE()) {
  122         case HIDMAP_CB_IS_ATTACHING:
  123                 evdev_support_event(evdev, EV_PWR);
  124                 /* TODO */
  125                 break;
  126         case HIDMAP_CB_IS_RUNNING:
  127                 data = ctx.data;
  128                 /* TODO */
  129                 break;
  130         default:
  131                 break;
  132         }
  133 
  134         return (0);
  135 }
  136 
  137 static int
  138 hpen_final_digi_cb(HIDMAP_CB_ARGS)
  139 {
  140         struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV();
  141 
  142         if (HIDMAP_CB_GET_STATE() == HIDMAP_CB_IS_ATTACHING)
  143                 evdev_support_prop(evdev, INPUT_PROP_POINTER);
  144 
  145         /* Do not execute callback at interrupt handler and detach */
  146         return (ENOSYS);
  147 }
  148 
  149 static int
  150 hpen_final_pen_cb(HIDMAP_CB_ARGS)
  151 {
  152         struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV();
  153 
  154         if (HIDMAP_CB_GET_STATE() == HIDMAP_CB_IS_ATTACHING)
  155                 evdev_support_prop(evdev, INPUT_PROP_DIRECT);
  156 
  157         /* Do not execute callback at interrupt handler and detach */
  158         return (ENOSYS);
  159 }
  160 
  161 static void
  162 hpen_identify(driver_t *driver, device_t parent)
  163 {
  164         const struct hid_device_info *hw = hid_get_device_info(parent);
  165 
  166         /* the report descriptor for the Wacom Graphire is broken */
  167         if (hw->idBus == BUS_USB && hw->idVendor == USB_VENDOR_WACOM) {
  168                 switch (hw->idProduct) {
  169                 case USB_PRODUCT_WACOM_GRAPHIRE:
  170                         hid_set_report_descr(parent,
  171                             hpen_graphire_report_descr,
  172                             sizeof(hpen_graphire_report_descr));
  173                         break;
  174 
  175                 case USB_PRODUCT_WACOM_GRAPHIRE3_4X5:
  176                         hid_set_report_descr(parent,
  177                             hpen_graphire3_4x5_report_descr,
  178                             sizeof(hpen_graphire3_4x5_report_descr));
  179                         break;
  180                 }
  181         }
  182 }
  183 
  184 static int
  185 hpen_probe(device_t dev)
  186 {
  187         struct hidmap *hm = device_get_softc(dev);
  188         int error;
  189         bool is_pen;
  190 
  191         error = HIDBUS_LOOKUP_DRIVER_INFO(dev, hpen_devs);
  192         if (error != 0)
  193                 return (error);
  194 
  195         hidmap_set_dev(hm, dev);
  196 
  197         /* Check if report descriptor belongs to a HID tablet device */
  198         is_pen = hidbus_get_usage(dev) == HID_USAGE2(HUP_DIGITIZERS, HUD_PEN);
  199         error = is_pen
  200             ? HIDMAP_ADD_MAP(hm, hpen_map_pen, NULL)
  201             : HIDMAP_ADD_MAP(hm, hpen_map_digi, NULL);
  202         if (error != 0)
  203                 return (error);
  204 
  205         hidbus_set_desc(dev, is_pen ? "Pen" : "Digitizer");
  206 
  207         return (BUS_PROBE_DEFAULT);
  208 }
  209 
  210 static int
  211 hpen_attach(device_t dev)
  212 {
  213         const struct hid_device_info *hw = hid_get_device_info(dev);
  214         struct hidmap *hm = device_get_softc(dev);
  215         int error;
  216 
  217         if (hw->idBus == BUS_USB && hw->idVendor == USB_VENDOR_WACOM &&
  218             hw->idProduct == USB_PRODUCT_WACOM_GRAPHIRE3_4X5) {
  219                 /*
  220                  * The Graphire3 needs 0x0202 to be written to
  221                  * feature report ID 2 before it'll start
  222                  * returning digitizer data.
  223                  */
  224                 static const uint8_t reportbuf[3] = {2, 2, 2};
  225                 error = hid_set_report(dev, reportbuf, sizeof(reportbuf),
  226                     HID_FEATURE_REPORT, reportbuf[0]);
  227                 if (error)
  228                         device_printf(dev, "set feature report failed, "
  229                             "error=%d (ignored)\n", error);
  230         }
  231 
  232         return (hidmap_attach(hm));
  233 }
  234 
  235 static int
  236 hpen_detach(device_t dev)
  237 {
  238         return (hidmap_detach(device_get_softc(dev)));
  239 }
  240 
  241 
  242 static devclass_t hpen_devclass;
  243 static device_method_t hpen_methods[] = {
  244         DEVMETHOD(device_identify,      hpen_identify),
  245         DEVMETHOD(device_probe,         hpen_probe),
  246         DEVMETHOD(device_attach,        hpen_attach),
  247         DEVMETHOD(device_detach,        hpen_detach),
  248 
  249         DEVMETHOD_END
  250 };
  251 
  252 DEFINE_CLASS_0(hpen, hpen_driver, hpen_methods, sizeof(struct hidmap));
  253 DRIVER_MODULE(hpen, hidbus, hpen_driver, hpen_devclass, NULL, 0);
  254 MODULE_DEPEND(hpen, hid, 1, 1, 1);
  255 MODULE_DEPEND(hpen, hidbus, 1, 1, 1);
  256 MODULE_DEPEND(hpen, hidmap, 1, 1, 1);
  257 MODULE_DEPEND(hpen, evdev, 1, 1, 1);
  258 MODULE_VERSION(hpen, 1);
  259 HID_PNP_INFO(hpen_devs);

Cache object: 25272a9ab0a2235ea68da0b193042e17


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