diff options
| -rw-r--r-- | drivers/hid/hid-asus.c | 218 | ||||
| -rw-r--r-- | drivers/hid/hid-core.c | 1 | ||||
| -rw-r--r-- | drivers/hid/hid-ids.h | 4 | ||||
| -rw-r--r-- | drivers/hid/hid-input.c | 196 | ||||
| -rw-r--r-- | drivers/hid/hid-logitech-hidpp.c | 2 | ||||
| -rw-r--r-- | drivers/hid/hid-multitouch.c | 2 | ||||
| -rw-r--r-- | drivers/hid/hid-ntrig.c | 2 | ||||
| -rw-r--r-- | drivers/hid/hid-sensor-custom.c | 2 | ||||
| -rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 1 | ||||
| -rw-r--r-- | drivers/hid/wacom_wac.c | 8 | ||||
| -rw-r--r-- | include/linux/hid.h | 2 |
11 files changed, 326 insertions, 112 deletions
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index a4a3c38bc145..50c294be8324 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/hid.h> | 29 | #include <linux/hid.h> |
| 30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
| 31 | #include <linux/input/mt.h> | 31 | #include <linux/input/mt.h> |
| 32 | #include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */ | ||
| 32 | 33 | ||
| 33 | #include "hid-ids.h" | 34 | #include "hid-ids.h" |
| 34 | 35 | ||
| @@ -38,24 +39,19 @@ MODULE_AUTHOR("Victor Vlasenko <victor.vlasenko@sysgears.com>"); | |||
| 38 | MODULE_AUTHOR("Frederik Wenigwieser <frederik.wenigwieser@gmail.com>"); | 39 | MODULE_AUTHOR("Frederik Wenigwieser <frederik.wenigwieser@gmail.com>"); |
| 39 | MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); | 40 | MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); |
| 40 | 41 | ||
| 42 | #define T100_TPAD_INTF 2 | ||
| 43 | |||
| 44 | #define T100CHI_MOUSE_REPORT_ID 0x06 | ||
| 41 | #define FEATURE_REPORT_ID 0x0d | 45 | #define FEATURE_REPORT_ID 0x0d |
| 42 | #define INPUT_REPORT_ID 0x5d | 46 | #define INPUT_REPORT_ID 0x5d |
| 43 | #define FEATURE_KBD_REPORT_ID 0x5a | 47 | #define FEATURE_KBD_REPORT_ID 0x5a |
| 44 | |||
| 45 | #define INPUT_REPORT_SIZE 28 | ||
| 46 | #define FEATURE_KBD_REPORT_SIZE 16 | 48 | #define FEATURE_KBD_REPORT_SIZE 16 |
| 47 | 49 | ||
| 48 | #define SUPPORT_KBD_BACKLIGHT BIT(0) | 50 | #define SUPPORT_KBD_BACKLIGHT BIT(0) |
| 49 | 51 | ||
| 50 | #define MAX_CONTACTS 5 | ||
| 51 | |||
| 52 | #define MAX_X 2794 | ||
| 53 | #define MAX_Y 1758 | ||
| 54 | #define MAX_TOUCH_MAJOR 8 | 52 | #define MAX_TOUCH_MAJOR 8 |
| 55 | #define MAX_PRESSURE 128 | 53 | #define MAX_PRESSURE 128 |
| 56 | 54 | ||
| 57 | #define CONTACT_DATA_SIZE 5 | ||
| 58 | |||
| 59 | #define BTN_LEFT_MASK 0x01 | 55 | #define BTN_LEFT_MASK 0x01 |
| 60 | #define CONTACT_TOOL_TYPE_MASK 0x80 | 56 | #define CONTACT_TOOL_TYPE_MASK 0x80 |
| 61 | #define CONTACT_X_MSB_MASK 0xf0 | 57 | #define CONTACT_X_MSB_MASK 0xf0 |
| @@ -70,6 +66,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); | |||
| 70 | #define QUIRK_NO_CONSUMER_USAGES BIT(4) | 66 | #define QUIRK_NO_CONSUMER_USAGES BIT(4) |
| 71 | #define QUIRK_USE_KBD_BACKLIGHT BIT(5) | 67 | #define QUIRK_USE_KBD_BACKLIGHT BIT(5) |
| 72 | #define QUIRK_T100_KEYBOARD BIT(6) | 68 | #define QUIRK_T100_KEYBOARD BIT(6) |
| 69 | #define QUIRK_T100CHI BIT(7) | ||
| 73 | 70 | ||
| 74 | #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ | 71 | #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ |
| 75 | QUIRK_NO_INIT_REPORTS | \ | 72 | QUIRK_NO_INIT_REPORTS | \ |
| @@ -88,19 +85,62 @@ struct asus_kbd_leds { | |||
| 88 | bool removed; | 85 | bool removed; |
| 89 | }; | 86 | }; |
| 90 | 87 | ||
| 88 | struct 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 | |||
| 91 | struct asus_drvdata { | 97 | struct asus_drvdata { |
| 92 | unsigned long quirks; | 98 | unsigned long quirks; |
| 93 | struct input_dev *input; | 99 | struct input_dev *input; |
| 94 | struct asus_kbd_leds *kbd_backlight; | 100 | struct asus_kbd_leds *kbd_backlight; |
| 101 | const struct asus_touchpad_info *tp; | ||
| 95 | bool enable_backlight; | 102 | bool enable_backlight; |
| 96 | }; | 103 | }; |
| 97 | 104 | ||
| 98 | static void asus_report_contact_down(struct input_dev *input, | 105 | static 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 | |||
| 112 | static 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 | |||
| 121 | static 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 | |||
| 130 | static void asus_report_contact_down(struct asus_drvdata *drvdat, | ||
| 99 | int toolType, u8 *data) | 131 | int toolType, u8 *data) |
| 100 | { | 132 | { |
| 101 | int touch_major, pressure; | 133 | struct input_dev *input = drvdat->input; |
| 102 | int x = (data[0] & CONTACT_X_MSB_MASK) << 4 | data[1]; | 134 | int touch_major, pressure, x, y; |
| 103 | int y = MAX_Y - ((data[0] & CONTACT_Y_MSB_MASK) << 8 | data[2]); | 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; | ||
| 104 | 144 | ||
| 105 | if (toolType == MT_TOOL_PALM) { | 145 | if (toolType == MT_TOOL_PALM) { |
| 106 | touch_major = MAX_TOUCH_MAJOR; | 146 | touch_major = MAX_TOUCH_MAJOR; |
| @@ -110,19 +150,20 @@ static void asus_report_contact_down(struct input_dev *input, | |||
| 110 | pressure = data[4] & CONTACT_PRESSURE_MASK; | 150 | pressure = data[4] & CONTACT_PRESSURE_MASK; |
| 111 | } | 151 | } |
| 112 | 152 | ||
| 113 | input_report_abs(input, ABS_MT_POSITION_X, x); | ||
| 114 | input_report_abs(input, ABS_MT_POSITION_Y, y); | ||
| 115 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major); | 153 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major); |
| 116 | input_report_abs(input, ABS_MT_PRESSURE, pressure); | 154 | input_report_abs(input, ABS_MT_PRESSURE, pressure); |
| 117 | } | 155 | } |
| 118 | 156 | ||
| 119 | /* Required for Synaptics Palm Detection */ | 157 | /* Required for Synaptics Palm Detection */ |
| 120 | static void asus_report_tool_width(struct input_dev *input) | 158 | static void asus_report_tool_width(struct asus_drvdata *drvdat) |
| 121 | { | 159 | { |
| 122 | struct input_mt *mt = input->mt; | 160 | struct input_mt *mt = drvdat->input->mt; |
| 123 | struct input_mt_slot *oldest; | 161 | struct input_mt_slot *oldest; |
| 124 | int oldid, count, i; | 162 | int oldid, count, i; |
| 125 | 163 | ||
| 164 | if (drvdat->tp->contact_size < 5) | ||
| 165 | return; | ||
| 166 | |||
| 126 | oldest = NULL; | 167 | oldest = NULL; |
| 127 | oldid = mt->trkid; | 168 | oldid = mt->trkid; |
| 128 | count = 0; | 169 | count = 0; |
| @@ -141,35 +182,42 @@ static void asus_report_tool_width(struct input_dev *input) | |||
| 141 | } | 182 | } |
| 142 | 183 | ||
| 143 | if (oldest) { | 184 | if (oldest) { |
| 144 | input_report_abs(input, ABS_TOOL_WIDTH, | 185 | input_report_abs(drvdat->input, ABS_TOOL_WIDTH, |
| 145 | input_mt_get_value(oldest, ABS_MT_TOUCH_MAJOR)); | 186 | input_mt_get_value(oldest, ABS_MT_TOUCH_MAJOR)); |
| 146 | } | 187 | } |
| 147 | } | 188 | } |
| 148 | 189 | ||
| 149 | static void asus_report_input(struct input_dev *input, u8 *data) | 190 | static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size) |
| 150 | { | 191 | { |
| 151 | int i; | 192 | int i, toolType = MT_TOOL_FINGER; |
| 152 | u8 *contactData = data + 2; | 193 | u8 *contactData = data + 2; |
| 153 | 194 | ||
| 154 | for (i = 0; i < MAX_CONTACTS; i++) { | 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++) { | ||
| 155 | bool down = !!(data[1] & BIT(i+3)); | 199 | bool down = !!(data[1] & BIT(i+3)); |
| 156 | int toolType = contactData[3] & CONTACT_TOOL_TYPE_MASK ? | 200 | |
| 201 | if (drvdat->tp->contact_size >= 5) | ||
| 202 | toolType = contactData[3] & CONTACT_TOOL_TYPE_MASK ? | ||
| 157 | MT_TOOL_PALM : MT_TOOL_FINGER; | 203 | MT_TOOL_PALM : MT_TOOL_FINGER; |
| 158 | 204 | ||
| 159 | input_mt_slot(input, i); | 205 | input_mt_slot(drvdat->input, i); |
| 160 | input_mt_report_slot_state(input, toolType, down); | 206 | input_mt_report_slot_state(drvdat->input, toolType, down); |
| 161 | 207 | ||
| 162 | if (down) { | 208 | if (down) { |
| 163 | asus_report_contact_down(input, toolType, contactData); | 209 | asus_report_contact_down(drvdat, toolType, contactData); |
| 164 | contactData += CONTACT_DATA_SIZE; | 210 | contactData += drvdat->tp->contact_size; |
| 165 | } | 211 | } |
| 166 | } | 212 | } |
| 167 | 213 | ||
| 168 | input_report_key(input, BTN_LEFT, data[1] & BTN_LEFT_MASK); | 214 | input_report_key(drvdat->input, BTN_LEFT, data[1] & BTN_LEFT_MASK); |
| 169 | asus_report_tool_width(input); | 215 | asus_report_tool_width(drvdat); |
| 216 | |||
| 217 | input_mt_sync_frame(drvdat->input); | ||
| 218 | input_sync(drvdat->input); | ||
| 170 | 219 | ||
| 171 | input_mt_sync_frame(input); | 220 | return 1; |
| 172 | input_sync(input); | ||
| 173 | } | 221 | } |
| 174 | 222 | ||
| 175 | static int asus_raw_event(struct hid_device *hdev, | 223 | static int asus_raw_event(struct hid_device *hdev, |
| @@ -177,12 +225,8 @@ static int asus_raw_event(struct hid_device *hdev, | |||
| 177 | { | 225 | { |
| 178 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); | 226 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); |
| 179 | 227 | ||
| 180 | if (drvdata->quirks & QUIRK_IS_MULTITOUCH && | 228 | if (drvdata->tp && data[0] == INPUT_REPORT_ID) |
| 181 | data[0] == INPUT_REPORT_ID && | 229 | return asus_report_input(drvdata, data, size); |
| 182 | size == INPUT_REPORT_SIZE) { | ||
| 183 | asus_report_input(drvdata->input, data); | ||
| 184 | return 1; | ||
| 185 | } | ||
| 186 | 230 | ||
| 187 | return 0; | 231 | return 0; |
| 188 | } | 232 | } |
| @@ -334,19 +378,35 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) | |||
| 334 | struct input_dev *input = hi->input; | 378 | struct input_dev *input = hi->input; |
| 335 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); | 379 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); |
| 336 | 380 | ||
| 337 | if (drvdata->quirks & QUIRK_IS_MULTITOUCH) { | 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) { | ||
| 338 | int ret; | 387 | int ret; |
| 339 | 388 | ||
| 340 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, MAX_X, 0, 0); | 389 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, |
| 341 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, MAX_Y, 0, 0); | 390 | drvdata->tp->max_x, 0, 0); |
| 342 | input_set_abs_params(input, ABS_TOOL_WIDTH, 0, MAX_TOUCH_MAJOR, 0, 0); | 391 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, |
| 343 | input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, MAX_TOUCH_MAJOR, 0, 0); | 392 | drvdata->tp->max_y, 0, 0); |
| 344 | input_set_abs_params(input, ABS_MT_PRESSURE, 0, MAX_PRESSURE, 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 | } | ||
| 345 | 404 | ||
| 346 | __set_bit(BTN_LEFT, input->keybit); | 405 | __set_bit(BTN_LEFT, input->keybit); |
| 347 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); | 406 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); |
| 348 | 407 | ||
| 349 | ret = input_mt_init_slots(input, MAX_CONTACTS, INPUT_MT_POINTER); | 408 | ret = input_mt_init_slots(input, drvdata->tp->max_contacts, |
| 409 | INPUT_MT_POINTER); | ||
| 350 | 410 | ||
| 351 | if (ret) { | 411 | if (ret) { |
| 352 | hid_err(hdev, "Asus input mt init slots failed: %d\n", ret); | 412 | hid_err(hdev, "Asus input mt init slots failed: %d\n", ret); |
| @@ -378,6 +438,26 @@ static int asus_input_mapping(struct hid_device *hdev, | |||
| 378 | return -1; | 438 | return -1; |
| 379 | } | 439 | } |
| 380 | 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 | |||
| 381 | /* ASUS-specific keyboard hotkeys */ | 461 | /* ASUS-specific keyboard hotkeys */ |
| 382 | if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) { | 462 | if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) { |
| 383 | set_bit(EV_REP, hi->input->evbit); | 463 | set_bit(EV_REP, hi->input->evbit); |
| @@ -496,7 +576,7 @@ static int __maybe_unused asus_reset_resume(struct hid_device *hdev) | |||
| 496 | { | 576 | { |
| 497 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); | 577 | struct asus_drvdata *drvdata = hid_get_drvdata(hdev); |
| 498 | 578 | ||
| 499 | if (drvdata->quirks & QUIRK_IS_MULTITOUCH) | 579 | if (drvdata->tp) |
| 500 | return asus_start_multitouch(hdev); | 580 | return asus_start_multitouch(hdev); |
| 501 | 581 | ||
| 502 | return 0; | 582 | return 0; |
| @@ -517,6 +597,28 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
| 517 | 597 | ||
| 518 | drvdata->quirks = id->driver_data; | 598 | drvdata->quirks = id->driver_data; |
| 519 | 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 | |||
| 520 | if (drvdata->quirks & QUIRK_NO_INIT_REPORTS) | 622 | if (drvdata->quirks & QUIRK_NO_INIT_REPORTS) |
| 521 | hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; | 623 | hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; |
| 522 | 624 | ||
| @@ -538,13 +640,13 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
| 538 | goto err_stop_hw; | 640 | goto err_stop_hw; |
| 539 | } | 641 | } |
| 540 | 642 | ||
| 541 | if (drvdata->quirks & QUIRK_IS_MULTITOUCH) { | 643 | if (drvdata->tp) { |
| 542 | drvdata->input->name = "Asus TouchPad"; | 644 | drvdata->input->name = "Asus TouchPad"; |
| 543 | } else { | 645 | } else { |
| 544 | drvdata->input->name = "Asus Keyboard"; | 646 | drvdata->input->name = "Asus Keyboard"; |
| 545 | } | 647 | } |
| 546 | 648 | ||
| 547 | if (drvdata->quirks & QUIRK_IS_MULTITOUCH) { | 649 | if (drvdata->tp) { |
| 548 | ret = asus_start_multitouch(hdev); | 650 | ret = asus_start_multitouch(hdev); |
| 549 | if (ret) | 651 | if (ret) |
| 550 | goto err_stop_hw; | 652 | goto err_stop_hw; |
| @@ -578,11 +680,34 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, | |||
| 578 | hid_info(hdev, "Fixing up Asus notebook report descriptor\n"); | 680 | hid_info(hdev, "Fixing up Asus notebook report descriptor\n"); |
| 579 | rdesc[55] = 0xdd; | 681 | rdesc[55] = 0xdd; |
| 580 | } | 682 | } |
| 683 | /* For the T100TA keyboard dock */ | ||
| 581 | if (drvdata->quirks & QUIRK_T100_KEYBOARD && | 684 | if (drvdata->quirks & QUIRK_T100_KEYBOARD && |
| 582 | *rsize == 76 && rdesc[73] == 0x81 && rdesc[74] == 0x01) { | 685 | *rsize == 76 && rdesc[73] == 0x81 && rdesc[74] == 0x01) { |
| 583 | hid_info(hdev, "Fixing up Asus T100 keyb report descriptor\n"); | 686 | hid_info(hdev, "Fixing up Asus T100 keyb report descriptor\n"); |
| 584 | rdesc[74] &= ~HID_MAIN_ITEM_CONSTANT; | 687 | rdesc[74] &= ~HID_MAIN_ITEM_CONSTANT; |
| 585 | } | 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 | } | ||
| 586 | 711 | ||
| 587 | return rdesc; | 712 | return rdesc; |
| 588 | } | 713 | } |
| @@ -602,6 +727,9 @@ static const struct hid_device_id asus_devices[] = { | |||
| 602 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) }, | 727 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) }, |
| 603 | { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) }, | 728 | { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) }, |
| 604 | { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) }, | 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 | |||
| 605 | { } | 733 | { } |
| 606 | }; | 734 | }; |
| 607 | MODULE_DEVICE_TABLE(hid, asus_devices); | 735 | MODULE_DEVICE_TABLE(hid, asus_devices); |
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 96e5457c2cc3..9bc91160819b 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
| @@ -1982,6 +1982,7 @@ static const struct hid_device_id hid_have_special_driver[] = { | |||
| 1982 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100_KEYBOARD) }, | 1982 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100_KEYBOARD) }, |
| 1983 | { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) }, | 1983 | { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) }, |
| 1984 | { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) }, | 1984 | { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) }, |
| 1985 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD) }, | ||
| 1985 | #endif | 1986 | #endif |
| 1986 | #if IS_ENABLED(CONFIG_HID_AUREAL) | 1987 | #if IS_ENABLED(CONFIG_HID_AUREAL) |
| 1987 | { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, | 1988 | { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, |
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c9ba4c6db74c..40d56b42c83b 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h | |||
| @@ -176,6 +176,7 @@ | |||
| 176 | #define USB_DEVICE_ID_ASUSTEK_LCM 0x1726 | 176 | #define USB_DEVICE_ID_ASUSTEK_LCM 0x1726 |
| 177 | #define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b | 177 | #define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b |
| 178 | #define USB_DEVICE_ID_ASUSTEK_T100_KEYBOARD 0x17e0 | 178 | #define USB_DEVICE_ID_ASUSTEK_T100_KEYBOARD 0x17e0 |
| 179 | #define USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD 0x8502 | ||
| 179 | #define USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD 0x8585 | 180 | #define USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD 0x8585 |
| 180 | #define USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD 0x0101 | 181 | #define USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD 0x0101 |
| 181 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854 | 182 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854 |
| @@ -666,7 +667,8 @@ | |||
| 666 | #define USB_VENDOR_ID_LOGITECH 0x046d | 667 | #define USB_VENDOR_ID_LOGITECH 0x046d |
| 667 | #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e | 668 | #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e |
| 668 | #define USB_DEVICE_ID_LOGITECH_T651 0xb00c | 669 | #define USB_DEVICE_ID_LOGITECH_T651 0xb00c |
| 669 | #define USB_DEVICE_ID_LOGITECH_C077 0xc007 | 670 | #define USB_DEVICE_ID_LOGITECH_C007 0xc007 |
| 671 | #define USB_DEVICE_ID_LOGITECH_C077 0xc077 | ||
| 670 | #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 | 672 | #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 |
| 671 | #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110 | 673 | #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110 |
| 672 | #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f | 674 | #define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f |
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index ccdff1ee1f0c..199f6a01fc62 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
| @@ -340,13 +340,45 @@ static unsigned find_battery_quirk(struct hid_device *hdev) | |||
| 340 | return quirks; | 340 | return quirks; |
| 341 | } | 341 | } |
| 342 | 342 | ||
| 343 | static int hidinput_scale_battery_capacity(struct hid_device *dev, | ||
| 344 | int value) | ||
| 345 | { | ||
| 346 | if (dev->battery_min < dev->battery_max && | ||
| 347 | value >= dev->battery_min && value <= dev->battery_max) | ||
| 348 | value = ((value - dev->battery_min) * 100) / | ||
| 349 | (dev->battery_max - dev->battery_min); | ||
| 350 | |||
| 351 | return value; | ||
| 352 | } | ||
| 353 | |||
| 354 | static int hidinput_query_battery_capacity(struct hid_device *dev) | ||
| 355 | { | ||
| 356 | u8 *buf; | ||
| 357 | int ret; | ||
| 358 | |||
| 359 | buf = kmalloc(2, GFP_KERNEL); | ||
| 360 | if (!buf) | ||
| 361 | return -ENOMEM; | ||
| 362 | |||
| 363 | ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2, | ||
| 364 | dev->battery_report_type, HID_REQ_GET_REPORT); | ||
| 365 | if (ret != 2) { | ||
| 366 | kfree(buf); | ||
| 367 | return -ENODATA; | ||
| 368 | } | ||
| 369 | |||
| 370 | ret = hidinput_scale_battery_capacity(dev, buf[1]); | ||
| 371 | kfree(buf); | ||
| 372 | return ret; | ||
| 373 | } | ||
| 374 | |||
| 343 | static int hidinput_get_battery_property(struct power_supply *psy, | 375 | static int hidinput_get_battery_property(struct power_supply *psy, |
| 344 | enum power_supply_property prop, | 376 | enum power_supply_property prop, |
| 345 | union power_supply_propval *val) | 377 | union power_supply_propval *val) |
| 346 | { | 378 | { |
| 347 | struct hid_device *dev = power_supply_get_drvdata(psy); | 379 | struct hid_device *dev = power_supply_get_drvdata(psy); |
| 380 | int value; | ||
| 348 | int ret = 0; | 381 | int ret = 0; |
| 349 | __u8 *buf; | ||
| 350 | 382 | ||
| 351 | switch (prop) { | 383 | switch (prop) { |
| 352 | case POWER_SUPPLY_PROP_PRESENT: | 384 | case POWER_SUPPLY_PROP_PRESENT: |
| @@ -355,29 +387,15 @@ static int hidinput_get_battery_property(struct power_supply *psy, | |||
| 355 | break; | 387 | break; |
| 356 | 388 | ||
| 357 | case POWER_SUPPLY_PROP_CAPACITY: | 389 | case POWER_SUPPLY_PROP_CAPACITY: |
| 358 | 390 | if (dev->battery_report_type == HID_FEATURE_REPORT) { | |
| 359 | buf = kmalloc(2 * sizeof(__u8), GFP_KERNEL); | 391 | value = hidinput_query_battery_capacity(dev); |
| 360 | if (!buf) { | 392 | if (value < 0) |
| 361 | ret = -ENOMEM; | 393 | return value; |
| 362 | break; | 394 | } else { |
| 363 | } | 395 | value = dev->battery_capacity; |
| 364 | ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2, | ||
| 365 | dev->battery_report_type, | ||
| 366 | HID_REQ_GET_REPORT); | ||
| 367 | |||
| 368 | if (ret != 2) { | ||
| 369 | ret = -ENODATA; | ||
| 370 | kfree(buf); | ||
| 371 | break; | ||
| 372 | } | 396 | } |
| 373 | ret = 0; | ||
| 374 | 397 | ||
| 375 | if (dev->battery_min < dev->battery_max && | 398 | val->intval = value; |
| 376 | buf[1] >= dev->battery_min && | ||
| 377 | buf[1] <= dev->battery_max) | ||
| 378 | val->intval = (100 * (buf[1] - dev->battery_min)) / | ||
| 379 | (dev->battery_max - dev->battery_min); | ||
| 380 | kfree(buf); | ||
| 381 | break; | 399 | break; |
| 382 | 400 | ||
| 383 | case POWER_SUPPLY_PROP_MODEL_NAME: | 401 | case POWER_SUPPLY_PROP_MODEL_NAME: |
| @@ -385,7 +403,22 @@ static int hidinput_get_battery_property(struct power_supply *psy, | |||
| 385 | break; | 403 | break; |
| 386 | 404 | ||
| 387 | case POWER_SUPPLY_PROP_STATUS: | 405 | case POWER_SUPPLY_PROP_STATUS: |
| 388 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | 406 | if (!dev->battery_reported && |
| 407 | dev->battery_report_type == HID_FEATURE_REPORT) { | ||
| 408 | value = hidinput_query_battery_capacity(dev); | ||
| 409 | if (value < 0) | ||
| 410 | return value; | ||
| 411 | |||
| 412 | dev->battery_capacity = value; | ||
| 413 | dev->battery_reported = true; | ||
| 414 | } | ||
| 415 | |||
| 416 | if (!dev->battery_reported) | ||
| 417 | val->intval = POWER_SUPPLY_STATUS_UNKNOWN; | ||
| 418 | else if (dev->battery_capacity == 100) | ||
| 419 | val->intval = POWER_SUPPLY_STATUS_FULL; | ||
| 420 | else | ||
| 421 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
| 389 | break; | 422 | break; |
| 390 | 423 | ||
| 391 | case POWER_SUPPLY_PROP_SCOPE: | 424 | case POWER_SUPPLY_PROP_SCOPE: |
| @@ -400,18 +433,16 @@ static int hidinput_get_battery_property(struct power_supply *psy, | |||
| 400 | return ret; | 433 | return ret; |
| 401 | } | 434 | } |
| 402 | 435 | ||
| 403 | static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field) | 436 | static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field) |
| 404 | { | 437 | { |
| 405 | struct power_supply_desc *psy_desc = NULL; | 438 | struct power_supply_desc *psy_desc; |
| 406 | struct power_supply_config psy_cfg = { .drv_data = dev, }; | 439 | struct power_supply_config psy_cfg = { .drv_data = dev, }; |
| 407 | unsigned quirks; | 440 | unsigned quirks; |
| 408 | s32 min, max; | 441 | s32 min, max; |
| 442 | int error; | ||
| 409 | 443 | ||
| 410 | if (field->usage->hid != HID_DC_BATTERYSTRENGTH) | 444 | if (dev->battery) |
| 411 | return false; /* no match */ | 445 | return 0; /* already initialized? */ |
| 412 | |||
| 413 | if (dev->battery != NULL) | ||
| 414 | goto out; /* already initialized? */ | ||
| 415 | 446 | ||
| 416 | quirks = find_battery_quirk(dev); | 447 | quirks = find_battery_quirk(dev); |
| 417 | 448 | ||
| @@ -419,16 +450,18 @@ static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, | |||
| 419 | dev->bus, dev->vendor, dev->product, dev->version, quirks); | 450 | dev->bus, dev->vendor, dev->product, dev->version, quirks); |
| 420 | 451 | ||
| 421 | if (quirks & HID_BATTERY_QUIRK_IGNORE) | 452 | if (quirks & HID_BATTERY_QUIRK_IGNORE) |
| 422 | goto out; | 453 | return 0; |
| 423 | 454 | ||
| 424 | psy_desc = kzalloc(sizeof(*psy_desc), GFP_KERNEL); | 455 | psy_desc = kzalloc(sizeof(*psy_desc), GFP_KERNEL); |
| 425 | if (psy_desc == NULL) | 456 | if (!psy_desc) |
| 426 | goto out; | 457 | return -ENOMEM; |
| 427 | 458 | ||
| 428 | psy_desc->name = kasprintf(GFP_KERNEL, "hid-%s-battery", dev->uniq); | 459 | psy_desc->name = kasprintf(GFP_KERNEL, "hid-%s-battery", |
| 429 | if (psy_desc->name == NULL) { | 460 | strlen(dev->uniq) ? |
| 430 | kfree(psy_desc); | 461 | dev->uniq : dev_name(&dev->dev)); |
| 431 | goto out; | 462 | if (!psy_desc->name) { |
| 463 | error = -ENOMEM; | ||
| 464 | goto err_free_mem; | ||
| 432 | } | 465 | } |
| 433 | 466 | ||
| 434 | psy_desc->type = POWER_SUPPLY_TYPE_BATTERY; | 467 | psy_desc->type = POWER_SUPPLY_TYPE_BATTERY; |
| @@ -455,17 +488,20 @@ static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, | |||
| 455 | 488 | ||
| 456 | dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg); | 489 | dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg); |
| 457 | if (IS_ERR(dev->battery)) { | 490 | if (IS_ERR(dev->battery)) { |
| 458 | hid_warn(dev, "can't register power supply: %ld\n", | 491 | error = PTR_ERR(dev->battery); |
| 459 | PTR_ERR(dev->battery)); | 492 | hid_warn(dev, "can't register power supply: %d\n", error); |
| 460 | kfree(psy_desc->name); | 493 | goto err_free_name; |
| 461 | kfree(psy_desc); | ||
| 462 | dev->battery = NULL; | ||
| 463 | } else { | ||
| 464 | power_supply_powers(dev->battery, &dev->dev); | ||
| 465 | } | 494 | } |
| 466 | 495 | ||
| 467 | out: | 496 | power_supply_powers(dev->battery, &dev->dev); |
| 468 | return true; | 497 | return 0; |
| 498 | |||
| 499 | err_free_name: | ||
| 500 | kfree(psy_desc->name); | ||
| 501 | err_free_mem: | ||
| 502 | kfree(psy_desc); | ||
| 503 | dev->battery = NULL; | ||
| 504 | return error; | ||
| 469 | } | 505 | } |
| 470 | 506 | ||
| 471 | static void hidinput_cleanup_battery(struct hid_device *dev) | 507 | static void hidinput_cleanup_battery(struct hid_device *dev) |
| @@ -481,16 +517,39 @@ static void hidinput_cleanup_battery(struct hid_device *dev) | |||
| 481 | kfree(psy_desc); | 517 | kfree(psy_desc); |
| 482 | dev->battery = NULL; | 518 | dev->battery = NULL; |
| 483 | } | 519 | } |
| 520 | |||
| 521 | static void hidinput_update_battery(struct hid_device *dev, int value) | ||
| 522 | { | ||
| 523 | int capacity; | ||
| 524 | |||
| 525 | if (!dev->battery) | ||
| 526 | return; | ||
| 527 | |||
| 528 | if (value == 0 || value < dev->battery_min || value > dev->battery_max) | ||
| 529 | return; | ||
| 530 | |||
| 531 | capacity = hidinput_scale_battery_capacity(dev, value); | ||
| 532 | |||
| 533 | if (!dev->battery_reported || capacity != dev->battery_capacity) { | ||
| 534 | dev->battery_capacity = capacity; | ||
| 535 | dev->battery_reported = true; | ||
| 536 | power_supply_changed(dev->battery); | ||
| 537 | } | ||
| 538 | } | ||
| 484 | #else /* !CONFIG_HID_BATTERY_STRENGTH */ | 539 | #else /* !CONFIG_HID_BATTERY_STRENGTH */ |
| 485 | static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, | 540 | static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, |
| 486 | struct hid_field *field) | 541 | struct hid_field *field) |
| 487 | { | 542 | { |
| 488 | return false; | 543 | return 0; |
| 489 | } | 544 | } |
| 490 | 545 | ||
| 491 | static void hidinput_cleanup_battery(struct hid_device *dev) | 546 | static void hidinput_cleanup_battery(struct hid_device *dev) |
| 492 | { | 547 | { |
| 493 | } | 548 | } |
| 549 | |||
| 550 | static void hidinput_update_battery(struct hid_device *dev, int value) | ||
| 551 | { | ||
| 552 | } | ||
| 494 | #endif /* CONFIG_HID_BATTERY_STRENGTH */ | 553 | #endif /* CONFIG_HID_BATTERY_STRENGTH */ |
| 495 | 554 | ||
| 496 | static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, | 555 | static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, |
| @@ -710,6 +769,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
| 710 | } | 769 | } |
| 711 | break; | 770 | break; |
| 712 | 771 | ||
| 772 | case 0x3b: /* Battery Strength */ | ||
| 773 | hidinput_setup_battery(device, HID_INPUT_REPORT, field); | ||
| 774 | usage->type = EV_PWR; | ||
| 775 | goto ignore; | ||
| 776 | |||
| 713 | case 0x3c: /* Invert */ | 777 | case 0x3c: /* Invert */ |
| 714 | map_key_clear(BTN_TOOL_RUBBER); | 778 | map_key_clear(BTN_TOOL_RUBBER); |
| 715 | break; | 779 | break; |
| @@ -944,11 +1008,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
| 944 | break; | 1008 | break; |
| 945 | 1009 | ||
| 946 | case HID_UP_GENDEVCTRLS: | 1010 | case HID_UP_GENDEVCTRLS: |
| 947 | if (hidinput_setup_battery(device, HID_INPUT_REPORT, field)) | 1011 | switch (usage->hid) { |
| 1012 | case HID_DC_BATTERYSTRENGTH: | ||
| 1013 | hidinput_setup_battery(device, HID_INPUT_REPORT, field); | ||
| 1014 | usage->type = EV_PWR; | ||
| 948 | goto ignore; | 1015 | goto ignore; |
| 949 | else | 1016 | } |
| 950 | goto unknown; | 1017 | goto unknown; |
| 951 | break; | ||
| 952 | 1018 | ||
| 953 | case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ | 1019 | case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ |
| 954 | set_bit(EV_REP, input->evbit); | 1020 | set_bit(EV_REP, input->evbit); |
| @@ -1031,7 +1097,6 @@ mapped: | |||
| 1031 | if (usage->code > max) | 1097 | if (usage->code > max) |
| 1032 | goto ignore; | 1098 | goto ignore; |
| 1033 | 1099 | ||
| 1034 | |||
| 1035 | if (usage->type == EV_ABS) { | 1100 | if (usage->type == EV_ABS) { |
| 1036 | 1101 | ||
| 1037 | int a = field->logical_minimum; | 1102 | int a = field->logical_minimum; |
| @@ -1090,14 +1155,19 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct | |||
| 1090 | struct input_dev *input; | 1155 | struct input_dev *input; |
| 1091 | unsigned *quirks = &hid->quirks; | 1156 | unsigned *quirks = &hid->quirks; |
| 1092 | 1157 | ||
| 1093 | if (!field->hidinput) | 1158 | if (!usage->type) |
| 1094 | return; | 1159 | return; |
| 1095 | 1160 | ||
| 1096 | input = field->hidinput->input; | 1161 | if (usage->type == EV_PWR) { |
| 1162 | hidinput_update_battery(hid, value); | ||
| 1163 | return; | ||
| 1164 | } | ||
| 1097 | 1165 | ||
| 1098 | if (!usage->type) | 1166 | if (!field->hidinput) |
| 1099 | return; | 1167 | return; |
| 1100 | 1168 | ||
| 1169 | input = field->hidinput->input; | ||
| 1170 | |||
| 1101 | if (usage->hat_min < usage->hat_max || usage->hat_dir) { | 1171 | if (usage->hat_min < usage->hat_max || usage->hat_dir) { |
| 1102 | int hat_dir = usage->hat_dir; | 1172 | int hat_dir = usage->hat_dir; |
| 1103 | if (!hat_dir) | 1173 | if (!hat_dir) |
| @@ -1373,6 +1443,7 @@ static void report_features(struct hid_device *hid) | |||
| 1373 | struct hid_driver *drv = hid->driver; | 1443 | struct hid_driver *drv = hid->driver; |
| 1374 | struct hid_report_enum *rep_enum; | 1444 | struct hid_report_enum *rep_enum; |
| 1375 | struct hid_report *rep; | 1445 | struct hid_report *rep; |
| 1446 | struct hid_usage *usage; | ||
| 1376 | int i, j; | 1447 | int i, j; |
| 1377 | 1448 | ||
| 1378 | rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; | 1449 | rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; |
| @@ -1383,12 +1454,15 @@ static void report_features(struct hid_device *hid) | |||
| 1383 | continue; | 1454 | continue; |
| 1384 | 1455 | ||
| 1385 | for (j = 0; j < rep->field[i]->maxusage; j++) { | 1456 | for (j = 0; j < rep->field[i]->maxusage; j++) { |
| 1457 | usage = &rep->field[i]->usage[j]; | ||
| 1458 | |||
| 1386 | /* Verify if Battery Strength feature is available */ | 1459 | /* Verify if Battery Strength feature is available */ |
| 1387 | hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]); | 1460 | if (usage->hid == HID_DC_BATTERYSTRENGTH) |
| 1461 | hidinput_setup_battery(hid, HID_FEATURE_REPORT, | ||
| 1462 | rep->field[i]); | ||
| 1388 | 1463 | ||
| 1389 | if (drv->feature_mapping) | 1464 | if (drv->feature_mapping) |
| 1390 | drv->feature_mapping(hid, rep->field[i], | 1465 | drv->feature_mapping(hid, rep->field[i], usage); |
| 1391 | rep->field[i]->usage + j); | ||
| 1392 | } | 1466 | } |
| 1393 | } | 1467 | } |
| 1394 | } | 1468 | } |
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 501e16a9227d..614054af904a 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c | |||
| @@ -2926,7 +2926,7 @@ static struct attribute *sysfs_attrs[] = { | |||
| 2926 | NULL | 2926 | NULL |
| 2927 | }; | 2927 | }; |
| 2928 | 2928 | ||
| 2929 | static struct attribute_group ps_attribute_group = { | 2929 | static const struct attribute_group ps_attribute_group = { |
| 2930 | .attrs = sysfs_attrs | 2930 | .attrs = sysfs_attrs |
| 2931 | }; | 2931 | }; |
| 2932 | 2932 | ||
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index aff20f4b6d97..e8acf93e6597 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c | |||
| @@ -341,7 +341,7 @@ static struct attribute *sysfs_attrs[] = { | |||
| 341 | NULL | 341 | NULL |
| 342 | }; | 342 | }; |
| 343 | 343 | ||
| 344 | static struct attribute_group mt_attribute_group = { | 344 | static const struct attribute_group mt_attribute_group = { |
| 345 | .attrs = sysfs_attrs | 345 | .attrs = sysfs_attrs |
| 346 | }; | 346 | }; |
| 347 | 347 | ||
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 1b0084d4af2e..3d121d8ee980 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c | |||
| @@ -445,7 +445,7 @@ static struct attribute *sysfs_attrs[] = { | |||
| 445 | NULL | 445 | NULL |
| 446 | }; | 446 | }; |
| 447 | 447 | ||
| 448 | static struct attribute_group ntrig_attribute_group = { | 448 | static const struct attribute_group ntrig_attribute_group = { |
| 449 | .attrs = sysfs_attrs | 449 | .attrs = sysfs_attrs |
| 450 | }; | 450 | }; |
| 451 | 451 | ||
diff --git a/drivers/hid/hid-sensor-custom.c b/drivers/hid/hid-sensor-custom.c index 3a84aaf1418b..fb86f86b9d92 100644 --- a/drivers/hid/hid-sensor-custom.c +++ b/drivers/hid/hid-sensor-custom.c | |||
| @@ -276,7 +276,7 @@ static struct attribute *enable_sensor_attrs[] = { | |||
| 276 | NULL, | 276 | NULL, |
| 277 | }; | 277 | }; |
| 278 | 278 | ||
| 279 | static struct attribute_group enable_sensor_attr_group = { | 279 | static const struct attribute_group enable_sensor_attr_group = { |
| 280 | .attrs = enable_sensor_attrs, | 280 | .attrs = enable_sensor_attrs, |
| 281 | }; | 281 | }; |
| 282 | 282 | ||
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index a88e7c7bea0a..a83fa76655b9 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c | |||
| @@ -99,6 +99,7 @@ static const struct hid_blacklist { | |||
| 99 | { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A, HID_QUIRK_ALWAYS_POLL }, | 99 | { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A, HID_QUIRK_ALWAYS_POLL }, |
| 100 | { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL }, | 100 | { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL }, |
| 101 | { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL }, | 101 | { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL }, |
| 102 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007, HID_QUIRK_ALWAYS_POLL }, | ||
| 102 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL }, | 103 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL }, |
| 103 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS, HID_QUIRK_NOGET }, | 104 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS, HID_QUIRK_NOGET }, |
| 104 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C01A, HID_QUIRK_ALWAYS_POLL }, | 105 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C01A, HID_QUIRK_ALWAYS_POLL }, |
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 9f940293ede4..bb17d7bbefd3 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c | |||
| @@ -1846,7 +1846,13 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev, | |||
| 1846 | features->device_type |= WACOM_DEVICETYPE_PAD; | 1846 | features->device_type |= WACOM_DEVICETYPE_PAD; |
| 1847 | break; | 1847 | break; |
| 1848 | case WACOM_HID_WD_TOUCHRINGSTATUS: | 1848 | case WACOM_HID_WD_TOUCHRINGSTATUS: |
| 1849 | wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0); | 1849 | /* |
| 1850 | * Only set up type/code association. Completely mapping | ||
| 1851 | * this usage may overwrite the axis resolution and range. | ||
| 1852 | */ | ||
| 1853 | usage->type = EV_ABS; | ||
| 1854 | usage->code = ABS_WHEEL; | ||
| 1855 | set_bit(EV_ABS, input->evbit); | ||
| 1850 | features->device_type |= WACOM_DEVICETYPE_PAD; | 1856 | features->device_type |= WACOM_DEVICETYPE_PAD; |
| 1851 | break; | 1857 | break; |
| 1852 | case WACOM_HID_WD_BUTTONCONFIG: | 1858 | case WACOM_HID_WD_BUTTONCONFIG: |
diff --git a/include/linux/hid.h b/include/linux/hid.h index 142409fc1ff3..1774a7887b9a 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
| @@ -541,10 +541,12 @@ struct hid_device { /* device report descriptor */ | |||
| 541 | * battery is non-NULL. | 541 | * battery is non-NULL. |
| 542 | */ | 542 | */ |
| 543 | struct power_supply *battery; | 543 | struct power_supply *battery; |
| 544 | __s32 battery_capacity; | ||
| 544 | __s32 battery_min; | 545 | __s32 battery_min; |
| 545 | __s32 battery_max; | 546 | __s32 battery_max; |
| 546 | __s32 battery_report_type; | 547 | __s32 battery_report_type; |
| 547 | __s32 battery_report_id; | 548 | __s32 battery_report_id; |
| 549 | bool battery_reported; | ||
| 548 | #endif | 550 | #endif |
| 549 | 551 | ||
| 550 | unsigned int status; /* see STAT flags above */ | 552 | unsigned int status; /* see STAT flags above */ |
