linux/drivers/hid/hid-elan.c
<<
>>
Prefs
   1/*
   2 * HID Driver for ELAN Touchpad
   3 *
   4 * Currently only supports touchpad found on HP Pavilion X2 10
   5 *
   6 * Copyright (c) 2016 Alexandrov Stanislav <neko@nya.ai>
   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/hid.h>
  15#include <linux/input/mt.h>
  16#include <linux/leds.h>
  17#include <linux/module.h>
  18#include <linux/usb.h>
  19
  20#include "hid-ids.h"
  21
  22#define ELAN_SINGLE_FINGER      0x81
  23#define ELAN_MT_FIRST_FINGER    0x82
  24#define ELAN_MT_SECOND_FINGER   0x83
  25#define ELAN_INPUT_REPORT_SIZE  8
  26
  27#define ELAN_MUTE_LED_REPORT    0xBC
  28#define ELAN_LED_REPORT_SIZE    8
  29
  30struct elan_touchpad_settings {
  31        u8 max_fingers;
  32        u16 max_x;
  33        u16 max_y;
  34        u8 max_area_x;
  35        u8 max_area_y;
  36        u8 max_w;
  37        int usb_bInterfaceNumber;
  38};
  39
  40struct elan_drvdata {
  41        struct input_dev *input;
  42        u8 prev_report[ELAN_INPUT_REPORT_SIZE];
  43        struct led_classdev mute_led;
  44        u8 mute_led_state;
  45        struct elan_touchpad_settings *settings;
  46};
  47
  48static int is_not_elan_touchpad(struct hid_device *hdev)
  49{
  50        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
  51        struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
  52
  53        return (intf->altsetting->desc.bInterfaceNumber != drvdata->settings->usb_bInterfaceNumber);
  54}
  55
  56static int elan_input_mapping(struct hid_device *hdev, struct hid_input *hi,
  57                              struct hid_field *field, struct hid_usage *usage,
  58                              unsigned long **bit, int *max)
  59{
  60        if (is_not_elan_touchpad(hdev))
  61                return 0;
  62
  63        if (field->report->id == ELAN_SINGLE_FINGER ||
  64            field->report->id == ELAN_MT_FIRST_FINGER ||
  65            field->report->id == ELAN_MT_SECOND_FINGER)
  66                return -1;
  67
  68        return 0;
  69}
  70
  71static int elan_input_configured(struct hid_device *hdev, struct hid_input *hi)
  72{
  73        int ret;
  74        struct input_dev *input;
  75        struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
  76
  77        if (is_not_elan_touchpad(hdev))
  78                return 0;
  79
  80        input = devm_input_allocate_device(&hdev->dev);
  81        if (!input)
  82                return -ENOMEM;
  83
  84        input->name = "Elan Touchpad";
  85        input->phys = hdev->phys;
  86        input->uniq = hdev->uniq;
  87        input->id.bustype = hdev->bus;
  88        input->id.vendor  = hdev->vendor;
  89        input->id.product = hdev->product;
  90        input->id.version = hdev->version;
  91        input->dev.parent = &hdev->dev;
  92
  93        input_set_abs_params(input, ABS_MT_POSITION_X, 0,
  94                             drvdata->settings->max_x, 0, 0);
  95        input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
  96                             drvdata->settings->max_y, 0, 0);
  97        input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0,
  98                             drvdata->settings->max_fingers, 0, 0);
  99        input_set_abs_params(input, ABS_TOOL_WIDTH, 0,
 100                             drvdata->settings->max_w, 0, 0);
 101
 102        __set_bit(BTN_LEFT, input->keybit);
 103        __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
 104
 105        ret = input_mt_init_slots(input, drvdata->settings->max_fingers,
 106                                  INPUT_MT_POINTER);
 107        if (ret) {
 108                hid_err(hdev, "Failed to init elan MT slots: %d\n", ret);
 109                return ret;
 110        }
 111
 112        ret = input_register_device(input);
 113        if (ret) {
 114                hid_err(hdev, "Failed to register elan input device: %d\n",
 115                        ret);
 116                input_free_device(input);
 117                return ret;
 118        }
 119
 120        drvdata->input = input;
 121
 122        return 0;
 123}
 124
 125static void elan_report_mt_slot(struct elan_drvdata *drvdata, u8 *data,
 126                                unsigned int slot_num)
 127{
 128        struct input_dev *input = drvdata->input;
 129        int x, y, w;
 130
 131        bool active = !!data;
 132
 133        input_mt_slot(input, slot_num);
 134        input_mt_report_slot_state(input, MT_TOOL_FINGER, active);
 135        if (active) {
 136                x = ((data[0] & 0xF0) << 4) | data[1];
 137                y = drvdata->settings->max_y -
 138                    (((data[0] & 0x07) << 8) | data[2]);
 139                w = data[4];
 140
 141                input_report_abs(input, ABS_MT_POSITION_X, x);
 142                input_report_abs(input, ABS_MT_POSITION_Y, y);
 143                input_report_abs(input, ABS_TOOL_WIDTH, w);
 144        }
 145}
 146
 147static void elan_report_input(struct elan_drvdata *drvdata, u8 *data)
 148{
 149        int i;
 150        struct input_dev *input = drvdata->input;
 151
 152        /*
 153         * There is 3 types of reports: for single touch,
 154         * for multitouch - first finger and for multitouch - second finger
 155         *
 156         * packet structure for ELAN_SINGLE_FINGER and ELAN_MT_FIRST_FINGER:
 157         *
 158         * byte 1: 1   0   0   0   0   0   0   1  // 0x81 or 0x82
 159         * byte 2: 0   0   0   0   0   0   0   0  // looks like unused
 160         * byte 3: f5  f4  f3  f2  f1  0   0   L
 161         * byte 4: x12 x11 x10 x9  0?  y11 y10 y9
 162         * byte 5: x8  x7  x6  x5  x4  x3  x2  x1
 163         * byte 6: y8  y7  y6  y5  y4  y3  y2  y1
 164         * byte 7: sy4 sy3 sy2 sy1 sx4 sx3 sx2 sx1
 165         * byte 8: w8  w7  w6  w5  w4  w3  w2  w1
 166         *
 167         * packet structure for ELAN_MT_SECOND_FINGER:
 168         *
 169         * byte 1: 1   0   0   0   0   0   1   1  // 0x83
 170         * byte 2: x12 x11 x10 x9  0   y11 y10 y9
 171         * byte 3: x8  x7  x6  x5  x4  x3  x2  x1
 172         * byte 4: y8  y7  y6  y5  y4  y3  y2  y1
 173         * byte 5: sy4 sy3 sy2 sy1 sx4 sx3 sx2 sx1
 174         * byte 6: w8  w7  w6  w5  w4  w3  w2  w1
 175         * byte 7: 0   0   0   0   0   0   0   0
 176         * byte 8: 0   0   0   0   0   0   0   0
 177         *
 178         * f5-f1: finger touch bits
 179         * L: clickpad button
 180         * sy / sx: not sure yet, but this looks like rectangular
 181         * area for finger
 182         * w: looks like finger width
 183         */
 184
 185        if (data[0] == ELAN_SINGLE_FINGER) {
 186                for (i = 0; i < drvdata->settings->max_fingers; i++) {
 187                        if (data[2] & BIT(i + 3))
 188                                elan_report_mt_slot(drvdata, data + 3, i);
 189                        else
 190                                elan_report_mt_slot(drvdata, NULL, i);
 191                }
 192                input_report_key(input, BTN_LEFT, data[2] & 0x01);
 193        }
 194        /*
 195         * When touched with two fingers Elan touchpad will emit two HID reports
 196         * first is ELAN_MT_FIRST_FINGER and second is ELAN_MT_SECOND_FINGER
 197         * we will save ELAN_MT_FIRST_FINGER report and wait for
 198         * ELAN_MT_SECOND_FINGER to finish multitouch
 199         */
 200        if (data[0] == ELAN_MT_FIRST_FINGER) {
 201                memcpy(drvdata->prev_report, data,
 202                       sizeof(drvdata->prev_report));
 203                return;
 204        }
 205
 206        if (data[0] == ELAN_MT_SECOND_FINGER) {
 207                int first = 0;
 208                u8 *prev_report = drvdata->prev_report;
 209
 210                if (prev_report[0] != ELAN_MT_FIRST_FINGER)
 211                        return;
 212
 213                for (i = 0; i < drvdata->settings->max_fingers; i++) {
 214                        if (prev_report[2] & BIT(i + 3)) {
 215                                if (!first) {
 216                                        first = 1;
 217                                        elan_report_mt_slot(drvdata, prev_report + 3, i);
 218                                } else {
 219                                        elan_report_mt_slot(drvdata, data + 1, i);
 220                                }
 221                        } else {
 222                                elan_report_mt_slot(drvdata, NULL, i);
 223                        }
 224                }
 225                input_report_key(input, BTN_LEFT, prev_report[2] & 0x01);
 226        }
 227
 228        input_mt_sync_frame(input);
 229        input_sync(input);
 230}
 231
 232static int elan_raw_event(struct hid_device *hdev,
 233                          struct hid_report *report, u8 *data, int size)
 234{
 235        struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
 236
 237        if (is_not_elan_touchpad(hdev))
 238                return 0;
 239
 240        if (data[0] == ELAN_SINGLE_FINGER ||
 241            data[0] == ELAN_MT_FIRST_FINGER ||
 242            data[0] == ELAN_MT_SECOND_FINGER) {
 243                if (size == ELAN_INPUT_REPORT_SIZE) {
 244                        elan_report_input(drvdata, data);
 245                        return 1;
 246                }
 247        }
 248
 249        return 0;
 250}
 251
 252static int elan_start_multitouch(struct hid_device *hdev)
 253{
 254        int ret;
 255
 256        /*
 257         * This byte sequence will enable multitouch mode and disable
 258         * mouse emulation
 259         */
 260        const unsigned char buf[] = { 0x0D, 0x00, 0x03, 0x21, 0x00 };
 261        unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL);
 262
 263        if (!dmabuf)
 264                return -ENOMEM;
 265
 266        ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, sizeof(buf),
 267                                 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 268
 269        kfree(dmabuf);
 270
 271        if (ret != sizeof(buf)) {
 272                hid_err(hdev, "Failed to start multitouch: %d\n", ret);
 273                return ret;
 274        }
 275
 276        return 0;
 277}
 278
 279static enum led_brightness elan_mute_led_get_brigtness(struct led_classdev *led_cdev)
 280{
 281        struct device *dev = led_cdev->dev->parent;
 282        struct hid_device *hdev = to_hid_device(dev);
 283        struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
 284
 285        return drvdata->mute_led_state;
 286}
 287
 288static int elan_mute_led_set_brigtness(struct led_classdev *led_cdev,
 289                                       enum led_brightness value)
 290{
 291        int ret;
 292        u8 led_state;
 293        struct device *dev = led_cdev->dev->parent;
 294        struct hid_device *hdev = to_hid_device(dev);
 295        struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
 296
 297        unsigned char *dmabuf = kzalloc(ELAN_LED_REPORT_SIZE, GFP_KERNEL);
 298
 299        if (!dmabuf)
 300                return -ENOMEM;
 301
 302        led_state = !!value;
 303
 304        dmabuf[0] = ELAN_MUTE_LED_REPORT;
 305        dmabuf[1] = 0x02;
 306        dmabuf[2] = led_state;
 307
 308        ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, ELAN_LED_REPORT_SIZE,
 309                                 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 310
 311        kfree(dmabuf);
 312
 313        if (ret != ELAN_LED_REPORT_SIZE) {
 314                hid_err(hdev, "Failed to set mute led brightness: %d\n", ret);
 315                return ret;
 316        }
 317
 318        drvdata->mute_led_state = led_state;
 319        return 0;
 320}
 321
 322static int elan_init_mute_led(struct hid_device *hdev)
 323{
 324        struct elan_drvdata *drvdata = hid_get_drvdata(hdev);
 325        struct led_classdev *mute_led = &drvdata->mute_led;
 326
 327        mute_led->name = "elan:red:mute";
 328        mute_led->brightness_get = elan_mute_led_get_brigtness;
 329        mute_led->brightness_set_blocking = elan_mute_led_set_brigtness;
 330        mute_led->max_brightness = LED_ON;
 331        mute_led->dev = &hdev->dev;
 332
 333        return devm_led_classdev_register(&hdev->dev, mute_led);
 334}
 335
 336static int elan_probe(struct hid_device *hdev, const struct hid_device_id *id)
 337{
 338        int ret;
 339        struct elan_drvdata *drvdata;
 340
 341        drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
 342
 343        if (!drvdata)
 344                return -ENOMEM;
 345
 346        drvdata->settings = (struct elan_touchpad_settings *)id->driver_data;
 347        hid_set_drvdata(hdev, drvdata);
 348
 349        ret = hid_parse(hdev);
 350        if (ret) {
 351                hid_err(hdev, "Hid Parse failed\n");
 352                return ret;
 353        }
 354
 355        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 356        if (ret) {
 357                hid_err(hdev, "Hid hw start failed\n");
 358                return ret;
 359        }
 360
 361        if (is_not_elan_touchpad(hdev))
 362                return 0;
 363
 364        if (!drvdata->input) {
 365                hid_err(hdev, "Input device is not registred\n");
 366                ret = -ENAVAIL;
 367                goto err;
 368        }
 369
 370        ret = elan_start_multitouch(hdev);
 371        if (ret)
 372                goto err;
 373
 374        ret = elan_init_mute_led(hdev);
 375        if (ret)
 376                goto err;
 377
 378        return 0;
 379err:
 380        hid_hw_stop(hdev);
 381        return ret;
 382}
 383
 384static void elan_remove(struct hid_device *hdev)
 385{
 386        hid_hw_stop(hdev);
 387}
 388
 389static const struct elan_touchpad_settings hp_x2_10_touchpad_data = {
 390        .max_fingers = 5,
 391        .max_x = 2930,
 392        .max_y = 1250,
 393        .max_area_x = 15,
 394        .max_area_y = 15,
 395        .max_w = 255,
 396        .usb_bInterfaceNumber = 1,
 397};
 398
 399static const struct hid_device_id elan_devices[] = {
 400        { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_HP_X2_10_COVER),
 401                (kernel_ulong_t)&hp_x2_10_touchpad_data},
 402        { }
 403};
 404
 405MODULE_DEVICE_TABLE(hid, elan_devices);
 406
 407static struct hid_driver elan_driver = {
 408        .name = "elan",
 409        .id_table = elan_devices,
 410        .input_mapping = elan_input_mapping,
 411        .input_configured = elan_input_configured,
 412        .raw_event = elan_raw_event,
 413        .probe = elan_probe,
 414        .remove = elan_remove,
 415};
 416
 417module_hid_driver(elan_driver);
 418
 419MODULE_LICENSE("GPL");
 420MODULE_AUTHOR("Alexandrov Stanislav");
 421MODULE_DESCRIPTION("Driver for HID ELAN Touchpads");
 422