linux/drivers/hid/hid-asus.c
<<
>>
Prefs
   1/*
   2 *  HID driver for Asus notebook built-in keyboard.
   3 *  Fixes small logical maximum to match usage maximum.
   4 *
   5 *  Currently supported devices are:
   6 *    EeeBook X205TA
   7 *    VivoBook E200HA
   8 *
   9 *  Copyright (c) 2016 Yusuke Fujimaki <usk.fujimaki@gmail.com>
  10 *
  11 *  This module based on hid-ortek by
  12 *  Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com>
  13 *  Copyright (c) 2011 Jiri Kosina
  14 *
  15 *  This module has been updated to add support for Asus i2c touchpad.
  16 *
  17 *  Copyright (c) 2016 Brendan McGrath <redmcg@redmandi.dyndns.org>
  18 *  Copyright (c) 2016 Victor Vlasenko <victor.vlasenko@sysgears.com>
  19 *  Copyright (c) 2016 Frederik Wenigwieser <frederik.wenigwieser@gmail.com>
  20 */
  21
  22/*
  23 * This program is free software; you can redistribute it and/or modify it
  24 * under the terms of the GNU General Public License as published by the Free
  25 * Software Foundation; either version 2 of the License, or (at your option)
  26 * any later version.
  27 */
  28
  29#include <linux/hid.h>
  30#include <linux/module.h>
  31#include <linux/input/mt.h>
  32#include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */
  33
  34#include "hid-ids.h"
  35
  36MODULE_AUTHOR("Yusuke Fujimaki <usk.fujimaki@gmail.com>");
  37MODULE_AUTHOR("Brendan McGrath <redmcg@redmandi.dyndns.org>");
  38MODULE_AUTHOR("Victor Vlasenko <victor.vlasenko@sysgears.com>");
  39MODULE_AUTHOR("Frederik Wenigwieser <frederik.wenigwieser@gmail.com>");
  40MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
  41
  42#define T100_TPAD_INTF 2
  43
  44#define T100CHI_MOUSE_REPORT_ID 0x06
  45#define FEATURE_REPORT_ID 0x0d
  46#define INPUT_REPORT_ID 0x5d
  47#define FEATURE_KBD_REPORT_ID 0x5a
  48#define FEATURE_KBD_REPORT_SIZE 16
  49
  50#define SUPPORT_KBD_BACKLIGHT BIT(0)
  51
  52#define MAX_TOUCH_MAJOR 8
  53#define MAX_PRESSURE 128
  54
  55#define BTN_LEFT_MASK 0x01
  56#define CONTACT_TOOL_TYPE_MASK 0x80
  57#define CONTACT_X_MSB_MASK 0xf0
  58#define CONTACT_Y_MSB_MASK 0x0f
  59#define CONTACT_TOUCH_MAJOR_MASK 0x07
  60#define CONTACT_PRESSURE_MASK 0x7f
  61
  62#define QUIRK_FIX_NOTEBOOK_REPORT       BIT(0)
  63#define QUIRK_NO_INIT_REPORTS           BIT(1)
  64#define QUIRK_SKIP_INPUT_MAPPING        BIT(2)
  65#define QUIRK_IS_MULTITOUCH             BIT(3)
  66#define QUIRK_NO_CONSUMER_USAGES        BIT(4)
  67#define QUIRK_USE_KBD_BACKLIGHT         BIT(5)
  68#define QUIRK_T100_KEYBOARD             BIT(6)
  69#define QUIRK_T100CHI                   BIT(7)
  70
  71#define I2C_KEYBOARD_QUIRKS                     (QUIRK_FIX_NOTEBOOK_REPORT | \
  72                                                 QUIRK_NO_INIT_REPORTS | \
  73                                                 QUIRK_NO_CONSUMER_USAGES)
  74#define I2C_TOUCHPAD_QUIRKS                     (QUIRK_NO_INIT_REPORTS | \
  75                                                 QUIRK_SKIP_INPUT_MAPPING | \
  76                                                 QUIRK_IS_MULTITOUCH)
  77
  78#define TRKID_SGN       ((TRKID_MAX + 1) >> 1)
  79
  80struct asus_kbd_leds {
  81        struct led_classdev cdev;
  82        struct hid_device *hdev;
  83        struct work_struct work;
  84        unsigned int brightness;
  85        bool removed;
  86};
  87
  88struct asus_touchpad_info {
  89        int max_x;
  90        int max_y;
  91        int res_x;
  92        int res_y;
  93        int contact_size;
  94        int max_contacts;
  95};
  96
  97struct asus_drvdata {
  98        unsigned long quirks;
  99        struct input_dev *input;
 100        struct asus_kbd_leds *kbd_backlight;
 101        const struct asus_touchpad_info *tp;
 102        bool enable_backlight;
 103};
 104
 105static const struct asus_touchpad_info asus_i2c_tp = {
 106        .max_x = 2794,
 107        .max_y = 1758,
 108        .contact_size = 5,
 109        .max_contacts = 5,
 110};
 111
 112static const struct asus_touchpad_info asus_t100ta_tp = {
 113        .max_x = 2240,
 114        .max_y = 1120,
 115        .res_x = 30, /* units/mm */
 116        .res_y = 27, /* units/mm */
 117        .contact_size = 5,
 118        .max_contacts = 5,
 119};
 120
 121static const struct asus_touchpad_info asus_t100chi_tp = {
 122        .max_x = 2640,
 123        .max_y = 1320,
 124        .res_x = 31, /* units/mm */
 125        .res_y = 29, /* units/mm */
 126        .contact_size = 3,
 127        .max_contacts = 4,
 128};
 129
 130static void asus_report_contact_down(struct asus_drvdata *drvdat,
 131                int toolType, u8 *data)
 132{
 133        struct input_dev *input = drvdat->input;
 134        int touch_major, pressure, x, y;
 135
 136        x = (data[0] & CONTACT_X_MSB_MASK) << 4 | data[1];
 137        y = drvdat->tp->max_y - ((data[0] & CONTACT_Y_MSB_MASK) << 8 | data[2]);
 138
 139        input_report_abs(input, ABS_MT_POSITION_X, x);
 140        input_report_abs(input, ABS_MT_POSITION_Y, y);
 141
 142        if (drvdat->tp->contact_size < 5)
 143                return;
 144
 145        if (toolType == MT_TOOL_PALM) {
 146                touch_major = MAX_TOUCH_MAJOR;
 147                pressure = MAX_PRESSURE;
 148        } else {
 149                touch_major = (data[3] >> 4) & CONTACT_TOUCH_MAJOR_MASK;
 150                pressure = data[4] & CONTACT_PRESSURE_MASK;
 151        }
 152
 153        input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major);
 154        input_report_abs(input, ABS_MT_PRESSURE, pressure);
 155}
 156
 157/* Required for Synaptics Palm Detection */
 158static void asus_report_tool_width(struct asus_drvdata *drvdat)
 159{
 160        struct input_mt *mt = drvdat->input->mt;
 161        struct input_mt_slot *oldest;
 162        int oldid, count, i;
 163
 164        if (drvdat->tp->contact_size < 5)
 165                return;
 166
 167        oldest = NULL;
 168        oldid = mt->trkid;
 169        count = 0;
 170
 171        for (i = 0; i < mt->num_slots; ++i) {
 172                struct input_mt_slot *ps = &mt->slots[i];
 173                int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
 174
 175                if (id < 0)
 176                        continue;
 177                if ((id - oldid) & TRKID_SGN) {
 178                        oldest = ps;
 179                        oldid = id;
 180                }
 181                count++;
 182        }
 183
 184        if (oldest) {
 185                input_report_abs(drvdat->input, ABS_TOOL_WIDTH,
 186                        input_mt_get_value(oldest, ABS_MT_TOUCH_MAJOR));
 187        }
 188}
 189
 190static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size)
 191{
 192        int i, toolType = MT_TOOL_FINGER;
 193        u8 *contactData = data + 2;
 194
 195        if (size != 3 + drvdat->tp->contact_size * drvdat->tp->max_contacts)
 196                return 0;
 197
 198        for (i = 0; i < drvdat->tp->max_contacts; i++) {
 199                bool down = !!(data[1] & BIT(i+3));
 200
 201                if (drvdat->tp->contact_size >= 5)
 202                        toolType = contactData[3] & CONTACT_TOOL_TYPE_MASK ?
 203                                                MT_TOOL_PALM : MT_TOOL_FINGER;
 204
 205                input_mt_slot(drvdat->input, i);
 206                input_mt_report_slot_state(drvdat->input, toolType, down);
 207
 208                if (down) {
 209                        asus_report_contact_down(drvdat, toolType, contactData);
 210                        contactData += drvdat->tp->contact_size;
 211                }
 212        }
 213
 214        input_report_key(drvdat->input, BTN_LEFT, data[1] & BTN_LEFT_MASK);
 215        asus_report_tool_width(drvdat);
 216
 217        input_mt_sync_frame(drvdat->input);
 218        input_sync(drvdat->input);
 219
 220        return 1;
 221}
 222
 223static int asus_raw_event(struct hid_device *hdev,
 224                struct hid_report *report, u8 *data, int size)
 225{
 226        struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
 227
 228        if (drvdata->tp && data[0] == INPUT_REPORT_ID)
 229                return asus_report_input(drvdata, data, size);
 230
 231        return 0;
 232}
 233
 234static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size)
 235{
 236        unsigned char *dmabuf;
 237        int ret;
 238
 239        dmabuf = kmemdup(buf, buf_size, GFP_KERNEL);
 240        if (!dmabuf)
 241                return -ENOMEM;
 242
 243        ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, dmabuf,
 244                                 buf_size, HID_FEATURE_REPORT,
 245                                 HID_REQ_SET_REPORT);
 246        kfree(dmabuf);
 247
 248        return ret;
 249}
 250
 251static int asus_kbd_init(struct hid_device *hdev)
 252{
 253        u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54,
 254                     0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 };
 255        int ret;
 256
 257        ret = asus_kbd_set_report(hdev, buf, sizeof(buf));
 258        if (ret < 0)
 259                hid_err(hdev, "Asus failed to send init command: %d\n", ret);
 260
 261        return ret;
 262}
 263
 264static int asus_kbd_get_functions(struct hid_device *hdev,
 265                                  unsigned char *kbd_func)
 266{
 267        u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x05, 0x20, 0x31, 0x00, 0x08 };
 268        u8 *readbuf;
 269        int ret;
 270
 271        ret = asus_kbd_set_report(hdev, buf, sizeof(buf));
 272        if (ret < 0) {
 273                hid_err(hdev, "Asus failed to send configuration command: %d\n", ret);
 274                return ret;
 275        }
 276
 277        readbuf = kzalloc(FEATURE_KBD_REPORT_SIZE, GFP_KERNEL);
 278        if (!readbuf)
 279                return -ENOMEM;
 280
 281        ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, readbuf,
 282                                 FEATURE_KBD_REPORT_SIZE, HID_FEATURE_REPORT,
 283                                 HID_REQ_GET_REPORT);
 284        if (ret < 0) {
 285                hid_err(hdev, "Asus failed to request functions: %d\n", ret);
 286                kfree(readbuf);
 287                return ret;
 288        }
 289
 290        *kbd_func = readbuf[6];
 291
 292        kfree(readbuf);
 293        return ret;
 294}
 295
 296static void asus_kbd_backlight_set(struct led_classdev *led_cdev,
 297                                   enum led_brightness brightness)
 298{
 299        struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
 300                                                 cdev);
 301        if (led->brightness == brightness)
 302                return;
 303
 304        led->brightness = brightness;
 305        schedule_work(&led->work);
 306}
 307
 308static enum led_brightness asus_kbd_backlight_get(struct led_classdev *led_cdev)
 309{
 310        struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
 311                                                 cdev);
 312
 313        return led->brightness;
 314}
 315
 316static void asus_kbd_backlight_work(struct work_struct *work)
 317{
 318        struct asus_kbd_leds *led = container_of(work, struct asus_kbd_leds, work);
 319        u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4, 0x00 };
 320        int ret;
 321
 322        if (led->removed)
 323                return;
 324
 325        buf[4] = led->brightness;
 326
 327        ret = asus_kbd_set_report(led->hdev, buf, sizeof(buf));
 328        if (ret < 0)
 329                hid_err(led->hdev, "Asus failed to set keyboard backlight: %d\n", ret);
 330}
 331
 332static int asus_kbd_register_leds(struct hid_device *hdev)
 333{
 334        struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
 335        unsigned char kbd_func;
 336        int ret;
 337
 338        /* Initialize keyboard */
 339        ret = asus_kbd_init(hdev);
 340        if (ret < 0)
 341                return ret;
 342
 343        /* Get keyboard functions */
 344        ret = asus_kbd_get_functions(hdev, &kbd_func);
 345        if (ret < 0)
 346                return ret;
 347
 348        /* Check for backlight support */
 349        if (!(kbd_func & SUPPORT_KBD_BACKLIGHT))
 350                return -ENODEV;
 351
 352        drvdata->kbd_backlight = devm_kzalloc(&hdev->dev,
 353                                              sizeof(struct asus_kbd_leds),
 354                                              GFP_KERNEL);
 355        if (!drvdata->kbd_backlight)
 356                return -ENOMEM;
 357
 358        drvdata->kbd_backlight->removed = false;
 359        drvdata->kbd_backlight->brightness = 0;
 360        drvdata->kbd_backlight->hdev = hdev;
 361        drvdata->kbd_backlight->cdev.name = "asus::kbd_backlight";
 362        drvdata->kbd_backlight->cdev.max_brightness = 3;
 363        drvdata->kbd_backlight->cdev.brightness_set = asus_kbd_backlight_set;
 364        drvdata->kbd_backlight->cdev.brightness_get = asus_kbd_backlight_get;
 365        INIT_WORK(&drvdata->kbd_backlight->work, asus_kbd_backlight_work);
 366
 367        ret = devm_led_classdev_register(&hdev->dev, &drvdata->kbd_backlight->cdev);
 368        if (ret < 0) {
 369                /* No need to have this still around */
 370                devm_kfree(&hdev->dev, drvdata->kbd_backlight);
 371        }
 372
 373        return ret;
 374}
 375
 376static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
 377{
 378        struct input_dev *input = hi->input;
 379        struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
 380
 381        /* T100CHI uses MULTI_INPUT, bind the touchpad to the mouse hid_input */
 382        if (drvdata->quirks & QUIRK_T100CHI &&
 383            hi->report->id != T100CHI_MOUSE_REPORT_ID)
 384                return 0;
 385
 386        if (drvdata->tp) {
 387                int ret;
 388
 389                input_set_abs_params(input, ABS_MT_POSITION_X, 0,
 390                                     drvdata->tp->max_x, 0, 0);
 391                input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
 392                                     drvdata->tp->max_y, 0, 0);
 393                input_abs_set_res(input, ABS_MT_POSITION_X, drvdata->tp->res_x);
 394                input_abs_set_res(input, ABS_MT_POSITION_Y, drvdata->tp->res_y);
 395
 396                if (drvdata->tp->contact_size >= 5) {
 397                        input_set_abs_params(input, ABS_TOOL_WIDTH, 0,
 398                                             MAX_TOUCH_MAJOR, 0, 0);
 399                        input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0,
 400                                             MAX_TOUCH_MAJOR, 0, 0);
 401                        input_set_abs_params(input, ABS_MT_PRESSURE, 0,
 402                                              MAX_PRESSURE, 0, 0);
 403                }
 404
 405                __set_bit(BTN_LEFT, input->keybit);
 406                __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
 407
 408                ret = input_mt_init_slots(input, drvdata->tp->max_contacts,
 409                                          INPUT_MT_POINTER);
 410
 411                if (ret) {
 412                        hid_err(hdev, "Asus input mt init slots failed: %d\n", ret);
 413                        return ret;
 414                }
 415        }
 416
 417        drvdata->input = input;
 418
 419        if (drvdata->enable_backlight && asus_kbd_register_leds(hdev))
 420                hid_warn(hdev, "Failed to initialize backlight.\n");
 421
 422        return 0;
 423}
 424
 425#define asus_map_key_clear(c)   hid_map_usage_clear(hi, usage, bit, \
 426                                                    max, EV_KEY, (c))
 427static int asus_input_mapping(struct hid_device *hdev,
 428                struct hid_input *hi, struct hid_field *field,
 429                struct hid_usage *usage, unsigned long **bit,
 430                int *max)
 431{
 432        struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
 433
 434        if (drvdata->quirks & QUIRK_SKIP_INPUT_MAPPING) {
 435                /* Don't map anything from the HID report.
 436                 * We do it all manually in asus_input_configured
 437                 */
 438                return -1;
 439        }
 440
 441        /*
 442         * Ignore a bunch of bogus collections in the T100CHI descriptor.
 443         * This avoids a bunch of non-functional hid_input devices getting
 444         * created because of the T100CHI using HID_QUIRK_MULTI_INPUT.
 445         */
 446        if (drvdata->quirks & QUIRK_T100CHI) {
 447                if (field->application == (HID_UP_GENDESK | 0x0080) ||
 448                    usage->hid == (HID_UP_GENDEVCTRLS | 0x0024) ||
 449                    usage->hid == (HID_UP_GENDEVCTRLS | 0x0025) ||
 450                    usage->hid == (HID_UP_GENDEVCTRLS | 0x0026))
 451                        return -1;
 452                /*
 453                 * We use the hid_input for the mouse report for the touchpad,
 454                 * keep the left button, to avoid the core removing it.
 455                 */
 456                if (field->application == HID_GD_MOUSE &&
 457                    usage->hid != (HID_UP_BUTTON | 1))
 458                        return -1;
 459        }
 460
 461        /* ASUS-specific keyboard hotkeys */
 462        if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) {
 463                set_bit(EV_REP, hi->input->evbit);
 464                switch (usage->hid & HID_USAGE) {
 465                case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN);      break;
 466                case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP);                break;
 467                case 0x35: asus_map_key_clear(KEY_DISPLAY_OFF);         break;
 468                case 0x6c: asus_map_key_clear(KEY_SLEEP);               break;
 469                case 0x82: asus_map_key_clear(KEY_CAMERA);              break;
 470                case 0x88: asus_map_key_clear(KEY_RFKILL);                      break;
 471                case 0xb5: asus_map_key_clear(KEY_CALC);                        break;
 472                case 0xc4: asus_map_key_clear(KEY_KBDILLUMUP);          break;
 473                case 0xc5: asus_map_key_clear(KEY_KBDILLUMDOWN);                break;
 474
 475                /* ASUS touchpad toggle */
 476                case 0x6b: asus_map_key_clear(KEY_F21);                 break;
 477
 478                /* ROG key */
 479                case 0x38: asus_map_key_clear(KEY_PROG1);               break;
 480
 481                /* Fn+C ASUS Splendid */
 482                case 0xba: asus_map_key_clear(KEY_PROG2);               break;
 483
 484                /* Fn+Space Power4Gear Hybrid */
 485                case 0x5c: asus_map_key_clear(KEY_PROG3);               break;
 486
 487                default:
 488                        /* ASUS lazily declares 256 usages, ignore the rest,
 489                         * as some make the keyboard appear as a pointer device. */
 490                        return -1;
 491                }
 492
 493                /*
 494                 * Check and enable backlight only on devices with UsagePage ==
 495                 * 0xff31 to avoid initializing the keyboard firmware multiple
 496                 * times on devices with multiple HID descriptors but same
 497                 * PID/VID.
 498                 */
 499                if (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT)
 500                        drvdata->enable_backlight = true;
 501
 502                return 1;
 503        }
 504
 505        if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) {
 506                set_bit(EV_REP, hi->input->evbit);
 507                switch (usage->hid & HID_USAGE) {
 508                case 0xff01: asus_map_key_clear(BTN_1); break;
 509                case 0xff02: asus_map_key_clear(BTN_2); break;
 510                case 0xff03: asus_map_key_clear(BTN_3); break;
 511                case 0xff04: asus_map_key_clear(BTN_4); break;
 512                case 0xff05: asus_map_key_clear(BTN_5); break;
 513                case 0xff06: asus_map_key_clear(BTN_6); break;
 514                case 0xff07: asus_map_key_clear(BTN_7); break;
 515                case 0xff08: asus_map_key_clear(BTN_8); break;
 516                case 0xff09: asus_map_key_clear(BTN_9); break;
 517                case 0xff0a: asus_map_key_clear(BTN_A); break;
 518                case 0xff0b: asus_map_key_clear(BTN_B); break;
 519                case 0x00f1: asus_map_key_clear(KEY_WLAN);      break;
 520                case 0x00f2: asus_map_key_clear(KEY_BRIGHTNESSDOWN);    break;
 521                case 0x00f3: asus_map_key_clear(KEY_BRIGHTNESSUP);      break;
 522                case 0x00f4: asus_map_key_clear(KEY_DISPLAY_OFF);       break;
 523                case 0x00f7: asus_map_key_clear(KEY_CAMERA);    break;
 524                case 0x00f8: asus_map_key_clear(KEY_PROG1);     break;
 525                default:
 526                        return 0;
 527                }
 528
 529                return 1;
 530        }
 531
 532        if (drvdata->quirks & QUIRK_NO_CONSUMER_USAGES &&
 533                (usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
 534                switch (usage->hid & HID_USAGE) {
 535                case 0xe2: /* Mute */
 536                case 0xe9: /* Volume up */
 537                case 0xea: /* Volume down */
 538                        return 0;
 539                default:
 540                        /* Ignore dummy Consumer usages which make the
 541                         * keyboard incorrectly appear as a pointer device.
 542                         */
 543                        return -1;
 544                }
 545        }
 546
 547        return 0;
 548}
 549
 550static int asus_start_multitouch(struct hid_device *hdev)
 551{
 552        int ret;
 553        const unsigned char buf[] = { FEATURE_REPORT_ID, 0x00, 0x03, 0x01, 0x00 };
 554        unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL);
 555
 556        if (!dmabuf) {
 557                ret = -ENOMEM;
 558                hid_err(hdev, "Asus failed to alloc dma buf: %d\n", ret);
 559                return ret;
 560        }
 561
 562        ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, sizeof(buf),
 563                                        HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 564
 565        kfree(dmabuf);
 566
 567        if (ret != sizeof(buf)) {
 568                hid_err(hdev, "Asus failed to start multitouch: %d\n", ret);
 569                return ret;
 570        }
 571
 572        return 0;
 573}
 574
 575static int __maybe_unused asus_reset_resume(struct hid_device *hdev)
 576{
 577        struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
 578
 579        if (drvdata->tp)
 580                return asus_start_multitouch(hdev);
 581
 582        return 0;
 583}
 584
 585static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
 586{
 587        int ret;
 588        struct asus_drvdata *drvdata;
 589
 590        drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
 591        if (drvdata == NULL) {
 592                hid_err(hdev, "Can't alloc Asus descriptor\n");
 593                return -ENOMEM;
 594        }
 595
 596        hid_set_drvdata(hdev, drvdata);
 597
 598        drvdata->quirks = id->driver_data;
 599
 600        if (drvdata->quirks & QUIRK_IS_MULTITOUCH)
 601                drvdata->tp = &asus_i2c_tp;
 602
 603        if (drvdata->quirks & QUIRK_T100_KEYBOARD) {
 604                struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 605
 606                if (intf->altsetting->desc.bInterfaceNumber == T100_TPAD_INTF) {
 607                        drvdata->quirks = QUIRK_SKIP_INPUT_MAPPING;
 608                        drvdata->tp = &asus_t100ta_tp;
 609                }
 610        }
 611
 612        if (drvdata->quirks & QUIRK_T100CHI) {
 613                /*
 614                 * All functionality is on a single HID interface and for
 615                 * userspace the touchpad must be a separate input_dev.
 616                 */
 617                hdev->quirks |= HID_QUIRK_MULTI_INPUT |
 618                                HID_QUIRK_NO_EMPTY_INPUT;
 619                drvdata->tp = &asus_t100chi_tp;
 620        }
 621
 622        if (drvdata->quirks & QUIRK_NO_INIT_REPORTS)
 623                hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
 624
 625        ret = hid_parse(hdev);
 626        if (ret) {
 627                hid_err(hdev, "Asus hid parse failed: %d\n", ret);
 628                return ret;
 629        }
 630
 631        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 632        if (ret) {
 633                hid_err(hdev, "Asus hw start failed: %d\n", ret);
 634                return ret;
 635        }
 636
 637        if (!drvdata->input) {
 638                hid_err(hdev, "Asus input not registered\n");
 639                ret = -ENOMEM;
 640                goto err_stop_hw;
 641        }
 642
 643        if (drvdata->tp) {
 644                drvdata->input->name = "Asus TouchPad";
 645        } else {
 646                drvdata->input->name = "Asus Keyboard";
 647        }
 648
 649        if (drvdata->tp) {
 650                ret = asus_start_multitouch(hdev);
 651                if (ret)
 652                        goto err_stop_hw;
 653        }
 654
 655        return 0;
 656err_stop_hw:
 657        hid_hw_stop(hdev);
 658        return ret;
 659}
 660
 661static void asus_remove(struct hid_device *hdev)
 662{
 663        struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
 664
 665        if (drvdata->kbd_backlight) {
 666                drvdata->kbd_backlight->removed = true;
 667                cancel_work_sync(&drvdata->kbd_backlight->work);
 668        }
 669
 670        hid_hw_stop(hdev);
 671}
 672
 673static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 674                unsigned int *rsize)
 675{
 676        struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
 677
 678        if (drvdata->quirks & QUIRK_FIX_NOTEBOOK_REPORT &&
 679                        *rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x65) {
 680                hid_info(hdev, "Fixing up Asus notebook report descriptor\n");
 681                rdesc[55] = 0xdd;
 682        }
 683        /* For the T100TA keyboard dock */
 684        if (drvdata->quirks & QUIRK_T100_KEYBOARD &&
 685                 *rsize == 76 && rdesc[73] == 0x81 && rdesc[74] == 0x01) {
 686                hid_info(hdev, "Fixing up Asus T100 keyb report descriptor\n");
 687                rdesc[74] &= ~HID_MAIN_ITEM_CONSTANT;
 688        }
 689        /* For the T100CHI keyboard dock */
 690        if (drvdata->quirks & QUIRK_T100CHI &&
 691                 *rsize == 403 && rdesc[388] == 0x09 && rdesc[389] == 0x76) {
 692                /*
 693                 * Change Usage (76h) to Usage Minimum (00h), Usage Maximum
 694                 * (FFh) and clear the flags in the Input() byte.
 695                 * Note the descriptor has a bogus 0 byte at the end so we
 696                 * only need 1 extra byte.
 697                 */
 698                *rsize = 404;
 699                rdesc = kmemdup(rdesc, *rsize, GFP_KERNEL);
 700                if (!rdesc)
 701                        return NULL;
 702
 703                hid_info(hdev, "Fixing up T100CHI keyb report descriptor\n");
 704                memmove(rdesc + 392, rdesc + 390, 12);
 705                rdesc[388] = 0x19;
 706                rdesc[389] = 0x00;
 707                rdesc[390] = 0x29;
 708                rdesc[391] = 0xff;
 709                rdesc[402] = 0x00;
 710        }
 711
 712        return rdesc;
 713}
 714
 715static const struct hid_device_id asus_devices[] = {
 716        { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK,
 717                USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD), I2C_KEYBOARD_QUIRKS},
 718        { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK,
 719                USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD), I2C_TOUCHPAD_QUIRKS },
 720        { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
 721                USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1) },
 722        { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
 723                USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2), QUIRK_USE_KBD_BACKLIGHT },
 724        { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
 725                USB_DEVICE_ID_ASUSTEK_T100_KEYBOARD),
 726          QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
 727        { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) },
 728        { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) },
 729        { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) },
 730        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK,
 731                USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD), QUIRK_T100CHI },
 732
 733        { }
 734};
 735MODULE_DEVICE_TABLE(hid, asus_devices);
 736
 737static struct hid_driver asus_driver = {
 738        .name                   = "asus",
 739        .id_table               = asus_devices,
 740        .report_fixup           = asus_report_fixup,
 741        .probe                  = asus_probe,
 742        .remove                 = asus_remove,
 743        .input_mapping          = asus_input_mapping,
 744        .input_configured       = asus_input_configured,
 745#ifdef CONFIG_PM
 746        .reset_resume           = asus_reset_resume,
 747#endif
 748        .raw_event              = asus_raw_event
 749};
 750module_hid_driver(asus_driver);
 751
 752MODULE_LICENSE("GPL");
 753