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 Val Packett <val@packett.cool>
    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_pen_cb;
   63 
   64 #define HPEN_MAP_BUT(usage, code)       \
   65         HIDMAP_KEY(HUP_DIGITIZERS, HUD_##usage, code)
   66 #define HPEN_MAP_ABS(usage, code)       \
   67         HIDMAP_ABS(HUP_DIGITIZERS, HUD_##usage, code)
   68 #define HPEN_MAP_ABS_GD(usage, code)    \
   69         HIDMAP_ABS(HUP_GENERIC_DESKTOP, HUG_##usage, code)
   70 #define HPEN_MAP_ABS_CB(usage, cb)      \
   71         HIDMAP_ABS_CB(HUP_DIGITIZERS, HUD_##usage, &cb)
   72 
   73 /* Generic map digitizer page map according to hut1_12v2.pdf */
   74 static const struct hidmap_item hpen_map_pen[] = {
   75     { HPEN_MAP_ABS_GD(X,                ABS_X),           .required = true },
   76     { HPEN_MAP_ABS_GD(Y,                ABS_Y),           .required = true },
   77     { HPEN_MAP_ABS(   TIP_PRESSURE,     ABS_PRESSURE) },
   78     { HPEN_MAP_ABS(   X_TILT,           ABS_TILT_X) },
   79     { HPEN_MAP_ABS(   Y_TILT,           ABS_TILT_Y) },
   80     { HPEN_MAP_ABS(   CONTACTID,        0),               .forbidden = true },
   81     { HPEN_MAP_ABS(   CONTACTCOUNT,     0),               .forbidden = true },
   82     { HPEN_MAP_ABS_CB(BATTERY_STRENGTH, hpen_battery_strenght_cb) },
   83     { HPEN_MAP_BUT(   TOUCH,            BTN_TOUCH) },
   84     { HPEN_MAP_BUT(   TIP_SWITCH,       BTN_TOUCH) },
   85     { HPEN_MAP_BUT(   SEC_TIP_SWITCH,   BTN_TOUCH) },
   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_pen_cb) },
   92 };
   93 
   94 static const struct hidmap_item hpen_map_stylus[] = {
   95     { HPEN_MAP_BUT(   IN_RANGE,         BTN_TOOL_PEN) },
   96 };
   97 static const struct hidmap_item hpen_map_finger[] = {
   98     { HPEN_MAP_BUT(   IN_RANGE,         BTN_TOOL_FINGER) },
   99 };
  100 
  101 static const struct hid_device_id hpen_devs[] = {
  102         { HID_TLC(HUP_DIGITIZERS, HUD_DIGITIZER) },
  103         { HID_TLC(HUP_DIGITIZERS, HUD_PEN) },
  104         { HID_TLC(HUP_DIGITIZERS, HUD_TOUCHSCREEN),
  105           HID_BVP(BUS_USB, USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL) },
  106 };
  107 
  108 /* Do not autoload legacy pen driver for all touchscreen */
  109 static const struct hid_device_id hpen_devs_no_load[] = {
  110         { HID_TLC(HUP_DIGITIZERS, HUD_TOUCHSCREEN) },
  111 };
  112 
  113 static int
  114 hpen_battery_strenght_cb(HIDMAP_CB_ARGS)
  115 {
  116         struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV();
  117 
  118         switch (HIDMAP_CB_GET_STATE()) {
  119         case HIDMAP_CB_IS_ATTACHING:
  120                 evdev_support_event(evdev, EV_PWR);
  121                 /* TODO */
  122                 break;
  123         case HIDMAP_CB_IS_RUNNING:
  124                 /* TODO */
  125                 break;
  126         default:
  127                 break;
  128         }
  129 
  130         return (0);
  131 }
  132 
  133 static int
  134 hpen_final_pen_cb(HIDMAP_CB_ARGS)
  135 {
  136         struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV();
  137 
  138         if (HIDMAP_CB_GET_STATE() == HIDMAP_CB_IS_ATTACHING) {
  139                 if (hidbus_get_usage(HIDMAP_CB_GET_DEV()) ==
  140                     HID_USAGE2(HUP_DIGITIZERS, HUD_DIGITIZER))
  141                         evdev_support_prop(evdev, INPUT_PROP_POINTER);
  142                 else
  143                         evdev_support_prop(evdev, INPUT_PROP_DIRECT);
  144         }
  145 
  146         /* Do not execute callback at interrupt handler and detach */
  147         return (ENOSYS);
  148 }
  149 
  150 static void
  151 hpen_identify(driver_t *driver, device_t parent)
  152 {
  153         const struct hid_device_info *hw = hid_get_device_info(parent);
  154 
  155         /* the report descriptor for the Wacom Graphire is broken */
  156         if (hw->idBus == BUS_USB && hw->idVendor == USB_VENDOR_WACOM) {
  157                 switch (hw->idProduct) {
  158                 case USB_PRODUCT_WACOM_GRAPHIRE:
  159                         hid_set_report_descr(parent,
  160                             hpen_graphire_report_descr,
  161                             sizeof(hpen_graphire_report_descr));
  162                         break;
  163 
  164                 case USB_PRODUCT_WACOM_GRAPHIRE3_4X5:
  165                         hid_set_report_descr(parent,
  166                             hpen_graphire3_4x5_report_descr,
  167                             sizeof(hpen_graphire3_4x5_report_descr));
  168                         break;
  169                 }
  170         }
  171 }
  172 
  173 static int
  174 hpen_probe(device_t dev)
  175 {
  176         struct hidmap *hm = device_get_softc(dev);
  177         const char *desc;
  178         void *d_ptr;
  179         hid_size_t d_len;
  180         int error;
  181 
  182         if (HIDBUS_LOOKUP_DRIVER_INFO(dev, hpen_devs_no_load) != 0) {
  183                 error = HIDBUS_LOOKUP_DRIVER_INFO(dev, hpen_devs);
  184                 if (error != 0)
  185                         return (error);
  186         }
  187 
  188         hidmap_set_dev(hm, dev);
  189 
  190         /* Check if report descriptor belongs to a HID pen device */
  191         error = HIDMAP_ADD_MAP(hm, hpen_map_pen, NULL);
  192         if (error != 0)
  193                 return (error);
  194 
  195         if (hid_get_report_descr(dev, &d_ptr, &d_len) != 0)
  196                 return (ENXIO);
  197 
  198         if (hidbus_is_collection(d_ptr, d_len,
  199             HID_USAGE2(HUP_DIGITIZERS, HUD_FINGER), hidbus_get_index(dev))) {
  200                 HIDMAP_ADD_MAP(hm, hpen_map_finger, NULL);
  201                 desc = "TouchScreen";
  202         } else {
  203                 HIDMAP_ADD_MAP(hm, hpen_map_stylus, NULL);
  204                 desc = "Pen";
  205         }
  206         if (hidbus_get_usage(dev) == HID_USAGE2(HUP_DIGITIZERS, HUD_DIGITIZER))
  207                 desc = "Digitizer";
  208 
  209         hidbus_set_desc(dev, desc);
  210 
  211         return (BUS_PROBE_DEFAULT);
  212 }
  213 
  214 static int
  215 hpen_attach(device_t dev)
  216 {
  217         const struct hid_device_info *hw = hid_get_device_info(dev);
  218         struct hidmap *hm = device_get_softc(dev);
  219         int error;
  220 
  221         if (hw->idBus == BUS_USB && hw->idVendor == USB_VENDOR_WACOM &&
  222             hw->idProduct == USB_PRODUCT_WACOM_GRAPHIRE3_4X5) {
  223                 /*
  224                  * The Graphire3 needs 0x0202 to be written to
  225                  * feature report ID 2 before it'll start
  226                  * returning digitizer data.
  227                  */
  228                 static const uint8_t reportbuf[3] = {2, 2, 2};
  229                 error = hid_set_report(dev, reportbuf, sizeof(reportbuf),
  230                     HID_FEATURE_REPORT, reportbuf[0]);
  231                 if (error)
  232                         device_printf(dev, "set feature report failed, "
  233                             "error=%d (ignored)\n", error);
  234         }
  235 
  236         return (hidmap_attach(hm));
  237 }
  238 
  239 static int
  240 hpen_detach(device_t dev)
  241 {
  242         return (hidmap_detach(device_get_softc(dev)));
  243 }
  244 
  245 
  246 static device_method_t hpen_methods[] = {
  247         DEVMETHOD(device_identify,      hpen_identify),
  248         DEVMETHOD(device_probe,         hpen_probe),
  249         DEVMETHOD(device_attach,        hpen_attach),
  250         DEVMETHOD(device_detach,        hpen_detach),
  251 
  252         DEVMETHOD_END
  253 };
  254 
  255 DEFINE_CLASS_0(hpen, hpen_driver, hpen_methods, sizeof(struct hidmap));
  256 DRIVER_MODULE(hpen, hidbus, hpen_driver, NULL, NULL);
  257 MODULE_DEPEND(hpen, hid, 1, 1, 1);
  258 MODULE_DEPEND(hpen, hidbus, 1, 1, 1);
  259 MODULE_DEPEND(hpen, hidmap, 1, 1, 1);
  260 MODULE_DEPEND(hpen, evdev, 1, 1, 1);
  261 MODULE_VERSION(hpen, 1);
  262 HID_PNP_INFO(hpen_devs);

Cache object: f2d0a56b504d7932b04ec60b30aa94a1


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