linux/drivers/hid/hid-huion.c
<<
>>
Prefs
   1/*
   2 *  HID driver for Huion devices not fully compliant with HID standard
   3 *
   4 *  Copyright (c) 2013 Martin Rusko
   5 */
   6
   7/*
   8 * This program is free software; you can redistribute it and/or modify it
   9 * under the terms of the GNU General Public License as published by the Free
  10 * Software Foundation; either version 2 of the License, or (at your option)
  11 * any later version.
  12 */
  13
  14#include <linux/device.h>
  15#include <linux/hid.h>
  16#include <linux/module.h>
  17#include <linux/usb.h>
  18#include "usbhid/usbhid.h"
  19
  20#include "hid-ids.h"
  21
  22/* Original Huion 580 report descriptor size */
  23#define HUION_580_RDESC_ORIG_SIZE       177
  24
  25/* Fixed Huion 580 report descriptor */
  26static __u8 huion_580_rdesc_fixed[] = {
  27        0x05, 0x0D,         /*  Usage Page (Digitizer),             */
  28        0x09, 0x02,         /*  Usage (Pen),                        */
  29        0xA1, 0x01,         /*  Collection (Application),           */
  30        0x85, 0x07,         /*      Report ID (7),                  */
  31        0x09, 0x20,         /*      Usage (Stylus),                 */
  32        0xA0,               /*      Collection (Physical),          */
  33        0x14,               /*          Logical Minimum (0),        */
  34        0x25, 0x01,         /*          Logical Maximum (1),        */
  35        0x75, 0x01,         /*          Report Size (1),            */
  36        0x09, 0x42,         /*          Usage (Tip Switch),         */
  37        0x09, 0x44,         /*          Usage (Barrel Switch),      */
  38        0x09, 0x46,         /*          Usage (Tablet Pick),        */
  39        0x95, 0x03,         /*          Report Count (3),           */
  40        0x81, 0x02,         /*          Input (Variable),           */
  41        0x95, 0x03,         /*          Report Count (3),           */
  42        0x81, 0x03,         /*          Input (Constant, Variable), */
  43        0x09, 0x32,         /*          Usage (In Range),           */
  44        0x95, 0x01,         /*          Report Count (1),           */
  45        0x81, 0x02,         /*          Input (Variable),           */
  46        0x95, 0x01,         /*          Report Count (1),           */
  47        0x81, 0x03,         /*          Input (Constant, Variable), */
  48        0x75, 0x10,         /*          Report Size (16),           */
  49        0x95, 0x01,         /*          Report Count (1),           */
  50        0xA4,               /*          Push,                       */
  51        0x05, 0x01,         /*          Usage Page (Desktop),       */
  52        0x65, 0x13,         /*          Unit (Inch),                */
  53        0x55, 0xFD,         /*          Unit Exponent (-3),         */
  54        0x34,               /*          Physical Minimum (0),       */
  55        0x09, 0x30,         /*          Usage (X),                  */
  56        0x46, 0x40, 0x1F,   /*          Physical Maximum (8000),    */
  57        0x26, 0x00, 0x7D,   /*          Logical Maximum (32000),    */
  58        0x81, 0x02,         /*          Input (Variable),           */
  59        0x09, 0x31,         /*          Usage (Y),                  */
  60        0x46, 0x88, 0x13,   /*          Physical Maximum (5000),    */
  61        0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
  62        0x81, 0x02,         /*          Input (Variable),           */
  63        0xB4,               /*          Pop,                        */
  64        0x09, 0x30,         /*          Usage (Tip Pressure),       */
  65        0x26, 0xFF, 0x07,   /*          Logical Maximum (2047),     */
  66        0x81, 0x02,         /*          Input (Variable),           */
  67        0xC0,               /*      End Collection,                 */
  68        0xC0                /*  End Collection                      */
  69};
  70
  71static __u8 *huion_report_fixup(struct hid_device *hdev, __u8 *rdesc,
  72                unsigned int *rsize)
  73{
  74        switch (hdev->product) {
  75        case USB_DEVICE_ID_HUION_580:
  76                if (*rsize == HUION_580_RDESC_ORIG_SIZE) {
  77                        rdesc = huion_580_rdesc_fixed;
  78                        *rsize = sizeof(huion_580_rdesc_fixed);
  79                }
  80                break;
  81        }
  82        return rdesc;
  83}
  84
  85/**
  86 * Enable fully-functional tablet mode by reading special string
  87 * descriptor.
  88 *
  89 * @hdev:       HID device
  90 *
  91 * The specific string descriptor and data were discovered by sniffing
  92 * the Windows driver traffic.
  93 */
  94static int huion_tablet_enable(struct hid_device *hdev)
  95{
  96        int rc;
  97        char buf[22];
  98
  99        rc = usb_string(hid_to_usb_dev(hdev), 0x64, buf, sizeof(buf));
 100        if (rc < 0)
 101                return rc;
 102
 103        return 0;
 104}
 105
 106static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)
 107{
 108        int ret;
 109        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 110
 111        /* Ignore interfaces 1 (mouse) and 2 (keyboard) for Huion 580 tablet,
 112         * as they are not used
 113         */
 114        switch (id->product) {
 115        case USB_DEVICE_ID_HUION_580:
 116                if (intf->cur_altsetting->desc.bInterfaceNumber != 0x00)
 117                        return -ENODEV;
 118                break;
 119        }
 120
 121        ret = hid_parse(hdev);
 122        if (ret) {
 123                hid_err(hdev, "parse failed\n");
 124                goto err;
 125        }
 126
 127        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 128        if (ret) {
 129                hid_err(hdev, "hw start failed\n");
 130                goto err;
 131        }
 132
 133        switch (id->product) {
 134        case USB_DEVICE_ID_HUION_580:
 135                ret = huion_tablet_enable(hdev);
 136                if (ret) {
 137                        hid_err(hdev, "tablet enabling failed\n");
 138                        goto enabling_err;
 139                }
 140                break;
 141        }
 142
 143        return 0;
 144enabling_err:
 145        hid_hw_stop(hdev);
 146err:
 147        return ret;
 148}
 149
 150static int huion_raw_event(struct hid_device *hdev, struct hid_report *report,
 151                        u8 *data, int size)
 152{
 153        /* If this is a pen input report then invert the in-range bit */
 154        if (report->type == HID_INPUT_REPORT && report->id == 0x07 && size >= 2)
 155                data[1] ^= 0x40;
 156
 157        return 0;
 158}
 159
 160static const struct hid_device_id huion_devices[] = {
 161        { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },
 162        { }
 163};
 164MODULE_DEVICE_TABLE(hid, huion_devices);
 165
 166static struct hid_driver huion_driver = {
 167        .name = "huion",
 168        .id_table = huion_devices,
 169        .probe = huion_probe,
 170        .report_fixup = huion_report_fixup,
 171        .raw_event = huion_raw_event,
 172};
 173module_hid_driver(huion_driver);
 174
 175MODULE_AUTHOR("Martin Rusko");
 176MODULE_DESCRIPTION("Huion HID driver");
 177MODULE_LICENSE("GPL");
 178