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_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         int32_t data;
  118 
  119         switch (HIDMAP_CB_GET_STATE()) {
  120         case HIDMAP_CB_IS_ATTACHING:
  121                 evdev_support_event(evdev, EV_PWR);
  122                 /* TODO */
  123                 break;
  124         case HIDMAP_CB_IS_RUNNING:
  125                 data = ctx.data;
  126                 /* TODO */
  127                 break;
  128         default:
  129                 break;
  130         }
  131 
  132         return (0);
  133 }
  134 
  135 static int
  136 hpen_final_pen_cb(HIDMAP_CB_ARGS)
  137 {
  138         struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV();
  139 
  140         if (HIDMAP_CB_GET_STATE() == HIDMAP_CB_IS_ATTACHING) {
  141                 if (hidbus_get_usage(HIDMAP_CB_GET_DEV()) ==
  142                     HID_USAGE2(HUP_DIGITIZERS, HUD_DIGITIZER))
  143                         evdev_support_prop(evdev, INPUT_PROP_POINTER);
  144                 else
  145                         evdev_support_prop(evdev, INPUT_PROP_DIRECT);
  146         }
  147 
  148         /* Do not execute callback at interrupt handler and detach */
  149         return (ENOSYS);
  150 }
  151 
  152 static void
  153 hpen_identify(driver_t *driver, device_t parent)
  154 {
  155         const struct hid_device_info *hw = hid_get_device_info(parent);
  156 
  157         /* the report descriptor for the Wacom Graphire is broken */
  158         if (hw->idBus == BUS_USB && hw->idVendor == USB_VENDOR_WACOM) {
  159                 switch (hw->idProduct) {
  160                 case USB_PRODUCT_WACOM_GRAPHIRE:
  161                         hid_set_report_descr(parent,
  162                             hpen_graphire_report_descr,
  163                             sizeof(hpen_graphire_report_descr));
  164                         break;
  165 
  166                 case USB_PRODUCT_WACOM_GRAPHIRE3_4X5:
  167                         hid_set_report_descr(parent,
  168                             hpen_graphire3_4x5_report_descr,
  169                             sizeof(hpen_graphire3_4x5_report_descr));
  170                         break;
  171                 }
  172         }
  173 }
  174 
  175 static int
  176 hpen_probe(device_t dev)
  177 {
  178         struct hidmap *hm = device_get_softc(dev);
  179         const char *desc;
  180         void *d_ptr;
  181         hid_size_t d_len;
  182         int error;
  183 
  184         if (HIDBUS_LOOKUP_DRIVER_INFO(dev, hpen_devs_no_load) != 0) {
  185                 error = HIDBUS_LOOKUP_DRIVER_INFO(dev, hpen_devs);
  186                 if (error != 0)
  187                         return (error);
  188         }
  189 
  190         hidmap_set_dev(hm, dev);
  191 
  192         /* Check if report descriptor belongs to a HID pen device */
  193         error = HIDMAP_ADD_MAP(hm, hpen_map_pen, NULL);
  194         if (error != 0)
  195                 return (error);
  196 
  197         if (hid_get_report_descr(dev, &d_ptr, &d_len) != 0)
  198                 return (ENXIO);
  199 
  200         if (hidbus_is_collection(d_ptr, d_len,
  201             HID_USAGE2(HUP_DIGITIZERS, HUD_FINGER), hidbus_get_index(dev))) {
  202                 HIDMAP_ADD_MAP(hm, hpen_map_finger, NULL);
  203                 desc = "TouchScreen";
  204         } else {
  205                 HIDMAP_ADD_MAP(hm, hpen_map_stylus, NULL);
  206                 desc = "Pen";
  207         }
  208         if (hidbus_get_usage(dev) == HID_USAGE2(HUP_DIGITIZERS, HUD_DIGITIZER))
  209                 desc = "Digitizer";
  210 
  211         hidbus_set_desc(dev, desc);
  212 
  213         return (BUS_PROBE_DEFAULT);
  214 }
  215 
  216 static int
  217 hpen_attach(device_t dev)
  218 {
  219         const struct hid_device_info *hw = hid_get_device_info(dev);
  220         struct hidmap *hm = device_get_softc(dev);
  221         int error;
  222 
  223         if (hw->idBus == BUS_USB && hw->idVendor == USB_VENDOR_WACOM &&
  224             hw->idProduct == USB_PRODUCT_WACOM_GRAPHIRE3_4X5) {
  225                 /*
  226                  * The Graphire3 needs 0x0202 to be written to
  227                  * feature report ID 2 before it'll start
  228                  * returning digitizer data.
  229                  */
  230                 static const uint8_t reportbuf[3] = {2, 2, 2};
  231                 error = hid_set_report(dev, reportbuf, sizeof(reportbuf),
  232                     HID_FEATURE_REPORT, reportbuf[0]);
  233                 if (error)
  234                         device_printf(dev, "set feature report failed, "
  235                             "error=%d (ignored)\n", error);
  236         }
  237 
  238         return (hidmap_attach(hm));
  239 }
  240 
  241 static int
  242 hpen_detach(device_t dev)
  243 {
  244         return (hidmap_detach(device_get_softc(dev)));
  245 }
  246 
  247 
  248 static devclass_t hpen_devclass;
  249 static device_method_t hpen_methods[] = {
  250         DEVMETHOD(device_identify,      hpen_identify),
  251         DEVMETHOD(device_probe,         hpen_probe),
  252         DEVMETHOD(device_attach,        hpen_attach),
  253         DEVMETHOD(device_detach,        hpen_detach),
  254 
  255         DEVMETHOD_END
  256 };
  257 
  258 DEFINE_CLASS_0(hpen, hpen_driver, hpen_methods, sizeof(struct hidmap));
  259 DRIVER_MODULE(hpen, hidbus, hpen_driver, hpen_devclass, NULL, 0);
  260 MODULE_DEPEND(hpen, hid, 1, 1, 1);
  261 MODULE_DEPEND(hpen, hidbus, 1, 1, 1);
  262 MODULE_DEPEND(hpen, hidmap, 1, 1, 1);
  263 MODULE_DEPEND(hpen, evdev, 1, 1, 1);
  264 MODULE_VERSION(hpen, 1);
  265 HID_PNP_INFO(hpen_devs);

Cache object: 0bc46c810d759b8f1b6530a1004a504c


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