linux/drivers/hid/hid-uclogic-core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *  HID driver for UC-Logic devices not fully compliant with HID standard
   4 *
   5 *  Copyright (c) 2010-2014 Nikolai Kondrashov
   6 *  Copyright (c) 2013 Martin Rusko
   7 */
   8
   9/*
  10 * This program is free software; you can redistribute it and/or modify it
  11 * under the terms of the GNU General Public License as published by the Free
  12 * Software Foundation; either version 2 of the License, or (at your option)
  13 * any later version.
  14 */
  15
  16#include <linux/device.h>
  17#include <linux/hid.h>
  18#include <linux/module.h>
  19#include <linux/timer.h>
  20#include "usbhid/usbhid.h"
  21#include "hid-uclogic-params.h"
  22
  23#include "hid-ids.h"
  24
  25/* Driver data */
  26struct uclogic_drvdata {
  27        /* Interface parameters */
  28        struct uclogic_params params;
  29        /* Pointer to the replacement report descriptor. NULL if none. */
  30        __u8 *desc_ptr;
  31        /*
  32         * Size of the replacement report descriptor.
  33         * Only valid if desc_ptr is not NULL
  34         */
  35        unsigned int desc_size;
  36        /* Pen input device */
  37        struct input_dev *pen_input;
  38        /* In-range timer */
  39        struct timer_list inrange_timer;
  40        /* Last rotary encoder state, or U8_MAX for none */
  41        u8 re_state;
  42};
  43
  44/**
  45 * uclogic_inrange_timeout - handle pen in-range state timeout.
  46 * Emulate input events normally generated when pen goes out of range for
  47 * tablets which don't report that.
  48 *
  49 * @t:  The timer the timeout handler is attached to, stored in a struct
  50 *      uclogic_drvdata.
  51 */
  52static void uclogic_inrange_timeout(struct timer_list *t)
  53{
  54        struct uclogic_drvdata *drvdata = from_timer(drvdata, t,
  55                                                        inrange_timer);
  56        struct input_dev *input = drvdata->pen_input;
  57
  58        if (input == NULL)
  59                return;
  60        input_report_abs(input, ABS_PRESSURE, 0);
  61        /* If BTN_TOUCH state is changing */
  62        if (test_bit(BTN_TOUCH, input->key)) {
  63                input_event(input, EV_MSC, MSC_SCAN,
  64                                /* Digitizer Tip Switch usage */
  65                                0xd0042);
  66                input_report_key(input, BTN_TOUCH, 0);
  67        }
  68        input_report_key(input, BTN_TOOL_PEN, 0);
  69        input_sync(input);
  70}
  71
  72static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
  73                                        unsigned int *rsize)
  74{
  75        struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
  76
  77        if (drvdata->desc_ptr != NULL) {
  78                rdesc = drvdata->desc_ptr;
  79                *rsize = drvdata->desc_size;
  80        }
  81        return rdesc;
  82}
  83
  84static int uclogic_input_mapping(struct hid_device *hdev,
  85                                 struct hid_input *hi,
  86                                 struct hid_field *field,
  87                                 struct hid_usage *usage,
  88                                 unsigned long **bit,
  89                                 int *max)
  90{
  91        struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
  92        struct uclogic_params *params = &drvdata->params;
  93
  94        /* discard the unused pen interface */
  95        if (params->pen_unused && (field->application == HID_DG_PEN))
  96                return -1;
  97
  98        /* let hid-core decide what to do */
  99        return 0;
 100}
 101
 102static int uclogic_input_configured(struct hid_device *hdev,
 103                struct hid_input *hi)
 104{
 105        struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
 106        struct uclogic_params *params = &drvdata->params;
 107        char *name;
 108        const char *suffix = NULL;
 109        struct hid_field *field;
 110        size_t len;
 111
 112        /* no report associated (HID_QUIRK_MULTI_INPUT not set) */
 113        if (!hi->report)
 114                return 0;
 115
 116        /*
 117         * If this is the input corresponding to the pen report
 118         * in need of tweaking.
 119         */
 120        if (hi->report->id == params->pen.id) {
 121                /* Remember the input device so we can simulate events */
 122                drvdata->pen_input = hi->input;
 123        }
 124
 125        field = hi->report->field[0];
 126
 127        switch (field->application) {
 128        case HID_GD_KEYBOARD:
 129                suffix = "Keyboard";
 130                break;
 131        case HID_GD_MOUSE:
 132                suffix = "Mouse";
 133                break;
 134        case HID_GD_KEYPAD:
 135                suffix = "Pad";
 136                break;
 137        case HID_DG_PEN:
 138                suffix = "Pen";
 139                break;
 140        case HID_CP_CONSUMER_CONTROL:
 141                suffix = "Consumer Control";
 142                break;
 143        case HID_GD_SYSTEM_CONTROL:
 144                suffix = "System Control";
 145                break;
 146        }
 147
 148        if (suffix) {
 149                len = strlen(hdev->name) + 2 + strlen(suffix);
 150                name = devm_kzalloc(&hi->input->dev, len, GFP_KERNEL);
 151                if (name) {
 152                        snprintf(name, len, "%s %s", hdev->name, suffix);
 153                        hi->input->name = name;
 154                }
 155        }
 156
 157        return 0;
 158}
 159
 160static int uclogic_probe(struct hid_device *hdev,
 161                const struct hid_device_id *id)
 162{
 163        int rc;
 164        struct uclogic_drvdata *drvdata = NULL;
 165        bool params_initialized = false;
 166
 167        /*
 168         * libinput requires the pad interface to be on a different node
 169         * than the pen, so use QUIRK_MULTI_INPUT for all tablets.
 170         */
 171        hdev->quirks |= HID_QUIRK_MULTI_INPUT;
 172
 173        /* Allocate and assign driver data */
 174        drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
 175        if (drvdata == NULL) {
 176                rc = -ENOMEM;
 177                goto failure;
 178        }
 179        timer_setup(&drvdata->inrange_timer, uclogic_inrange_timeout, 0);
 180        drvdata->re_state = U8_MAX;
 181        hid_set_drvdata(hdev, drvdata);
 182
 183        /* Initialize the device and retrieve interface parameters */
 184        rc = uclogic_params_init(&drvdata->params, hdev);
 185        if (rc != 0) {
 186                hid_err(hdev, "failed probing parameters: %d\n", rc);
 187                goto failure;
 188        }
 189        params_initialized = true;
 190        hid_dbg(hdev, "parameters:\n" UCLOGIC_PARAMS_FMT_STR,
 191                UCLOGIC_PARAMS_FMT_ARGS(&drvdata->params));
 192        if (drvdata->params.invalid) {
 193                hid_info(hdev, "interface is invalid, ignoring\n");
 194                rc = -ENODEV;
 195                goto failure;
 196        }
 197
 198        /* Generate replacement report descriptor */
 199        rc = uclogic_params_get_desc(&drvdata->params,
 200                                     &drvdata->desc_ptr,
 201                                     &drvdata->desc_size);
 202        if (rc) {
 203                hid_err(hdev,
 204                        "failed generating replacement report descriptor: %d\n",
 205                        rc);
 206                goto failure;
 207        }
 208
 209        rc = hid_parse(hdev);
 210        if (rc) {
 211                hid_err(hdev, "parse failed\n");
 212                goto failure;
 213        }
 214
 215        rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 216        if (rc) {
 217                hid_err(hdev, "hw start failed\n");
 218                goto failure;
 219        }
 220
 221        return 0;
 222failure:
 223        /* Assume "remove" might not be called if "probe" failed */
 224        if (params_initialized)
 225                uclogic_params_cleanup(&drvdata->params);
 226        return rc;
 227}
 228
 229#ifdef CONFIG_PM
 230static int uclogic_resume(struct hid_device *hdev)
 231{
 232        int rc;
 233        struct uclogic_params params;
 234
 235        /* Re-initialize the device, but discard parameters */
 236        rc = uclogic_params_init(&params, hdev);
 237        if (rc != 0)
 238                hid_err(hdev, "failed to re-initialize the device\n");
 239        else
 240                uclogic_params_cleanup(&params);
 241
 242        return rc;
 243}
 244#endif
 245
 246static int uclogic_raw_event(struct hid_device *hdev,
 247                                struct hid_report *report,
 248                                u8 *data, int size)
 249{
 250        struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
 251        struct uclogic_params *params = &drvdata->params;
 252
 253        /* Tweak pen reports, if necessary */
 254        if (!params->pen_unused &&
 255            (report->type == HID_INPUT_REPORT) &&
 256            (report->id == params->pen.id) &&
 257            (size >= 2)) {
 258                /* If it's the "virtual" frame controls report */
 259                if (params->frame.id != 0 &&
 260                    data[1] & params->pen_frame_flag) {
 261                        /* Change to virtual frame controls report ID */
 262                        data[0] = params->frame.id;
 263                        return 0;
 264                }
 265                /* If in-range reports are inverted */
 266                if (params->pen.inrange ==
 267                        UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) {
 268                        /* Invert the in-range bit */
 269                        data[1] ^= 0x40;
 270                }
 271                /*
 272                 * If report contains fragmented high-resolution pen
 273                 * coordinates
 274                 */
 275                if (size >= 10 && params->pen.fragmented_hires) {
 276                        u8 pressure_low_byte;
 277                        u8 pressure_high_byte;
 278
 279                        /* Lift pressure bytes */
 280                        pressure_low_byte = data[6];
 281                        pressure_high_byte = data[7];
 282                        /*
 283                         * Move Y coord to make space for high-order X
 284                         * coord byte
 285                         */
 286                        data[6] = data[5];
 287                        data[5] = data[4];
 288                        /* Move high-order X coord byte */
 289                        data[4] = data[8];
 290                        /* Move high-order Y coord byte */
 291                        data[7] = data[9];
 292                        /* Place pressure bytes */
 293                        data[8] = pressure_low_byte;
 294                        data[9] = pressure_high_byte;
 295                }
 296                /* If we need to emulate in-range detection */
 297                if (params->pen.inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
 298                        /* Set in-range bit */
 299                        data[1] |= 0x40;
 300                        /* (Re-)start in-range timeout */
 301                        mod_timer(&drvdata->inrange_timer,
 302                                        jiffies + msecs_to_jiffies(100));
 303                }
 304        }
 305
 306        /* Tweak frame control reports, if necessary */
 307        if ((report->type == HID_INPUT_REPORT) &&
 308            (report->id == params->frame.id)) {
 309                /* If need to, and can, set pad device ID for Wacom drivers */
 310                if (params->frame.dev_id_byte > 0 &&
 311                    params->frame.dev_id_byte < size) {
 312                        data[params->frame.dev_id_byte] = 0xf;
 313                }
 314                /* If need to, and can, read rotary encoder state change */
 315                if (params->frame.re_lsb > 0 &&
 316                    params->frame.re_lsb / 8 < size) {
 317                        unsigned int byte = params->frame.re_lsb / 8;
 318                        unsigned int bit = params->frame.re_lsb % 8;
 319
 320                        u8 change;
 321                        u8 prev_state = drvdata->re_state;
 322                        /* Read Gray-coded state */
 323                        u8 state = (data[byte] >> bit) & 0x3;
 324                        /* Encode state change into 2-bit signed integer */
 325                        if ((prev_state == 1 && state == 0) ||
 326                            (prev_state == 2 && state == 3)) {
 327                                change = 1;
 328                        } else if ((prev_state == 2 && state == 0) ||
 329                                   (prev_state == 1 && state == 3)) {
 330                                change = 3;
 331                        } else {
 332                                change = 0;
 333                        }
 334                        /* Write change */
 335                        data[byte] = (data[byte] & ~((u8)3 << bit)) |
 336                                        (change << bit);
 337                        /* Remember state */
 338                        drvdata->re_state = state;
 339                }
 340        }
 341
 342        return 0;
 343}
 344
 345static void uclogic_remove(struct hid_device *hdev)
 346{
 347        struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
 348
 349        del_timer_sync(&drvdata->inrange_timer);
 350        hid_hw_stop(hdev);
 351        kfree(drvdata->desc_ptr);
 352        uclogic_params_cleanup(&drvdata->params);
 353}
 354
 355static const struct hid_device_id uclogic_devices[] = {
 356        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 357                                USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
 358        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 359                                USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
 360        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 361                                USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
 362        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 363                                USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
 364        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 365                                USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
 366        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 367                                USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
 368        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 369                                USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
 370        { HID_USB_DEVICE(USB_VENDOR_ID_HUION,
 371                                USB_DEVICE_ID_HUION_TABLET) },
 372        { HID_USB_DEVICE(USB_VENDOR_ID_HUION,
 373                                USB_DEVICE_ID_HUION_HS64) },
 374        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 375                                USB_DEVICE_ID_HUION_TABLET) },
 376        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 377                                USB_DEVICE_ID_YIYNOVA_TABLET) },
 378        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 379                                USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81) },
 380        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 381                                USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45) },
 382        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 383                                USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47) },
 384        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 385                                USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) },
 386        { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER,
 387                                USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
 388        { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
 389                                USB_DEVICE_ID_UGEE_TABLET_G5) },
 390        { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
 391                                USB_DEVICE_ID_UGEE_TABLET_EX07S) },
 392        { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
 393                                USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720) },
 394        { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
 395                                USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540) },
 396        { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
 397                                USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) },
 398        { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
 399                                USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) },
 400        { }
 401};
 402MODULE_DEVICE_TABLE(hid, uclogic_devices);
 403
 404static struct hid_driver uclogic_driver = {
 405        .name = "uclogic",
 406        .id_table = uclogic_devices,
 407        .probe = uclogic_probe,
 408        .remove = uclogic_remove,
 409        .report_fixup = uclogic_report_fixup,
 410        .raw_event = uclogic_raw_event,
 411        .input_mapping = uclogic_input_mapping,
 412        .input_configured = uclogic_input_configured,
 413#ifdef CONFIG_PM
 414        .resume           = uclogic_resume,
 415        .reset_resume     = uclogic_resume,
 416#endif
 417};
 418module_hid_driver(uclogic_driver);
 419
 420MODULE_AUTHOR("Martin Rusko");
 421MODULE_AUTHOR("Nikolai Kondrashov");
 422MODULE_LICENSE("GPL");
 423