.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2000-2001 Vojtech Pavlik |
---|
3 | 4 | * Copyright (c) 2006-2010 Jiri Kosina |
---|
.. | .. |
---|
6 | 7 | */ |
---|
7 | 8 | |
---|
8 | 9 | /* |
---|
9 | | - * This program is free software; you can redistribute it and/or modify |
---|
10 | | - * it under the terms of the GNU General Public License as published by |
---|
11 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
12 | | - * (at your option) any later version. |
---|
13 | | - * |
---|
14 | | - * This program is distributed in the hope that it will be useful, |
---|
15 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
16 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
17 | | - * GNU General Public License for more details. |
---|
18 | | - * |
---|
19 | | - * You should have received a copy of the GNU General Public License |
---|
20 | | - * along with this program; if not, write to the Free Software |
---|
21 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
22 | 10 | * |
---|
23 | 11 | * Should you need to contact me, the author, you can do so either by |
---|
24 | 12 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: |
---|
.. | .. |
---|
335 | 323 | USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD), |
---|
336 | 324 | HID_BATTERY_QUIRK_IGNORE }, |
---|
337 | 325 | { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN), |
---|
| 326 | + HID_BATTERY_QUIRK_IGNORE }, |
---|
| 327 | + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_SPECTRE_X360_15), |
---|
| 328 | + HID_BATTERY_QUIRK_IGNORE }, |
---|
| 329 | + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN), |
---|
338 | 330 | HID_BATTERY_QUIRK_IGNORE }, |
---|
339 | 331 | {} |
---|
340 | 332 | }; |
---|
.. | .. |
---|
683 | 675 | break; |
---|
684 | 676 | } |
---|
685 | 677 | |
---|
| 678 | + if ((usage->hid & 0xf0) == 0xa0) { /* SystemControl */ |
---|
| 679 | + switch (usage->hid & 0xf) { |
---|
| 680 | + case 0x9: map_key_clear(KEY_MICMUTE); break; |
---|
| 681 | + default: goto ignore; |
---|
| 682 | + } |
---|
| 683 | + break; |
---|
| 684 | + } |
---|
| 685 | + |
---|
686 | 686 | if ((usage->hid & 0xf0) == 0xb0) { /* SC - Display */ |
---|
687 | 687 | switch (usage->hid & 0xf) { |
---|
688 | 688 | case 0x05: map_key_clear(KEY_SWITCHVIDEOMODE); break; |
---|
.. | .. |
---|
726 | 726 | map_abs_clear(usage->hid & 0xf); |
---|
727 | 727 | break; |
---|
728 | 728 | |
---|
729 | | - case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: |
---|
| 729 | + case HID_GD_WHEEL: |
---|
| 730 | + if (field->flags & HID_MAIN_ITEM_RELATIVE) { |
---|
| 731 | + set_bit(REL_WHEEL, input->relbit); |
---|
| 732 | + map_rel(REL_WHEEL_HI_RES); |
---|
| 733 | + } else { |
---|
| 734 | + map_abs(usage->hid & 0xf); |
---|
| 735 | + } |
---|
| 736 | + break; |
---|
| 737 | + case HID_GD_SLIDER: case HID_GD_DIAL: |
---|
730 | 738 | if (field->flags & HID_MAIN_ITEM_RELATIVE) |
---|
731 | 739 | map_rel(usage->hid & 0xf); |
---|
732 | 740 | else |
---|
.. | .. |
---|
775 | 783 | break; |
---|
776 | 784 | |
---|
777 | 785 | case HID_UP_DIGITIZER: |
---|
| 786 | + if ((field->application & 0xff) == 0x01) /* Digitizer */ |
---|
| 787 | + __set_bit(INPUT_PROP_POINTER, input->propbit); |
---|
| 788 | + else if ((field->application & 0xff) == 0x02) /* Pen */ |
---|
| 789 | + __set_bit(INPUT_PROP_DIRECT, input->propbit); |
---|
| 790 | + |
---|
778 | 791 | switch (usage->hid & 0xff) { |
---|
779 | 792 | case 0x00: /* Undefined */ |
---|
780 | 793 | goto ignore; |
---|
.. | .. |
---|
900 | 913 | case 0x06a: map_key_clear(KEY_GREEN); break; |
---|
901 | 914 | case 0x06b: map_key_clear(KEY_BLUE); break; |
---|
902 | 915 | case 0x06c: map_key_clear(KEY_YELLOW); break; |
---|
903 | | - case 0x06d: map_key_clear(KEY_ZOOM); break; |
---|
| 916 | + case 0x06d: map_key_clear(KEY_ASPECT_RATIO); break; |
---|
904 | 917 | |
---|
905 | 918 | case 0x06f: map_key_clear(KEY_BRIGHTNESSUP); break; |
---|
906 | 919 | case 0x070: map_key_clear(KEY_BRIGHTNESSDOWN); break; |
---|
.. | .. |
---|
954 | 967 | |
---|
955 | 968 | case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break; |
---|
956 | 969 | case 0x0cf: map_key_clear(KEY_VOICECOMMAND); break; |
---|
| 970 | + |
---|
| 971 | + case 0x0d8: map_key_clear(KEY_DICTATE); break; |
---|
| 972 | + case 0x0d9: map_key_clear(KEY_EMOJI_PICKER); break; |
---|
| 973 | + |
---|
957 | 974 | case 0x0e0: map_abs_clear(ABS_VOLUME); break; |
---|
958 | 975 | case 0x0e2: map_key_clear(KEY_MUTE); break; |
---|
959 | 976 | case 0x0e5: map_key_clear(KEY_BASSBOOST); break; |
---|
.. | .. |
---|
1024 | 1041 | case 0x22d: map_key_clear(KEY_ZOOMIN); break; |
---|
1025 | 1042 | case 0x22e: map_key_clear(KEY_ZOOMOUT); break; |
---|
1026 | 1043 | case 0x22f: map_key_clear(KEY_ZOOMRESET); break; |
---|
| 1044 | + case 0x232: map_key_clear(KEY_FULL_SCREEN); break; |
---|
1027 | 1045 | case 0x233: map_key_clear(KEY_SCROLLUP); break; |
---|
1028 | 1046 | case 0x234: map_key_clear(KEY_SCROLLDOWN); break; |
---|
1029 | | - case 0x238: map_rel(REL_HWHEEL); break; |
---|
| 1047 | + case 0x238: /* AC Pan */ |
---|
| 1048 | + set_bit(REL_HWHEEL, input->relbit); |
---|
| 1049 | + map_rel(REL_HWHEEL_HI_RES); |
---|
| 1050 | + break; |
---|
1030 | 1051 | case 0x23d: map_key_clear(KEY_EDIT); break; |
---|
1031 | 1052 | case 0x25f: map_key_clear(KEY_CANCEL); break; |
---|
1032 | 1053 | case 0x269: map_key_clear(KEY_INSERT); break; |
---|
.. | .. |
---|
1036 | 1057 | case 0x289: map_key_clear(KEY_REPLY); break; |
---|
1037 | 1058 | case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; |
---|
1038 | 1059 | case 0x28c: map_key_clear(KEY_SEND); break; |
---|
| 1060 | + |
---|
| 1061 | + case 0x29d: map_key_clear(KEY_KBD_LAYOUT_NEXT); break; |
---|
| 1062 | + |
---|
| 1063 | + case 0x2a2: map_key_clear(KEY_ALL_APPLICATIONS); break; |
---|
1039 | 1064 | |
---|
1040 | 1065 | case 0x2c7: map_key_clear(KEY_KBDINPUTASSIST_PREV); break; |
---|
1041 | 1066 | case 0x2c8: map_key_clear(KEY_KBDINPUTASSIST_NEXT); break; |
---|
.. | .. |
---|
1228 | 1253 | usage->code = 0; |
---|
1229 | 1254 | } |
---|
1230 | 1255 | |
---|
| 1256 | +static void hidinput_handle_scroll(struct hid_usage *usage, |
---|
| 1257 | + struct input_dev *input, |
---|
| 1258 | + __s32 value) |
---|
| 1259 | +{ |
---|
| 1260 | + int code; |
---|
| 1261 | + int hi_res, lo_res; |
---|
| 1262 | + |
---|
| 1263 | + if (value == 0) |
---|
| 1264 | + return; |
---|
| 1265 | + |
---|
| 1266 | + if (usage->code == REL_WHEEL_HI_RES) |
---|
| 1267 | + code = REL_WHEEL; |
---|
| 1268 | + else |
---|
| 1269 | + code = REL_HWHEEL; |
---|
| 1270 | + |
---|
| 1271 | + /* |
---|
| 1272 | + * Windows reports one wheel click as value 120. Where a high-res |
---|
| 1273 | + * scroll wheel is present, a fraction of 120 is reported instead. |
---|
| 1274 | + * Our REL_WHEEL_HI_RES axis does the same because all HW must |
---|
| 1275 | + * adhere to the 120 expectation. |
---|
| 1276 | + */ |
---|
| 1277 | + hi_res = value * 120/usage->resolution_multiplier; |
---|
| 1278 | + |
---|
| 1279 | + usage->wheel_accumulated += hi_res; |
---|
| 1280 | + lo_res = usage->wheel_accumulated/120; |
---|
| 1281 | + if (lo_res) |
---|
| 1282 | + usage->wheel_accumulated -= lo_res * 120; |
---|
| 1283 | + |
---|
| 1284 | + input_event(input, EV_REL, code, lo_res); |
---|
| 1285 | + input_event(input, EV_REL, usage->code, hi_res); |
---|
| 1286 | +} |
---|
| 1287 | + |
---|
1231 | 1288 | void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) |
---|
1232 | 1289 | { |
---|
1233 | 1290 | struct input_dev *input; |
---|
.. | .. |
---|
1295 | 1352 | |
---|
1296 | 1353 | if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ |
---|
1297 | 1354 | return; |
---|
| 1355 | + |
---|
| 1356 | + if ((usage->type == EV_REL) && (usage->code == REL_WHEEL_HI_RES || |
---|
| 1357 | + usage->code == REL_HWHEEL_HI_RES)) { |
---|
| 1358 | + hidinput_handle_scroll(usage, input, value); |
---|
| 1359 | + return; |
---|
| 1360 | + } |
---|
1298 | 1361 | |
---|
1299 | 1362 | if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) && |
---|
1300 | 1363 | (usage->code == ABS_VOLUME)) { |
---|
.. | .. |
---|
1523 | 1586 | hid_hw_close(hid); |
---|
1524 | 1587 | } |
---|
1525 | 1588 | |
---|
| 1589 | +static bool __hidinput_change_resolution_multipliers(struct hid_device *hid, |
---|
| 1590 | + struct hid_report *report, bool use_logical_max) |
---|
| 1591 | +{ |
---|
| 1592 | + struct hid_usage *usage; |
---|
| 1593 | + bool update_needed = false; |
---|
| 1594 | + bool get_report_completed = false; |
---|
| 1595 | + int i, j; |
---|
| 1596 | + |
---|
| 1597 | + if (report->maxfield == 0) |
---|
| 1598 | + return false; |
---|
| 1599 | + |
---|
| 1600 | + for (i = 0; i < report->maxfield; i++) { |
---|
| 1601 | + __s32 value = use_logical_max ? |
---|
| 1602 | + report->field[i]->logical_maximum : |
---|
| 1603 | + report->field[i]->logical_minimum; |
---|
| 1604 | + |
---|
| 1605 | + /* There is no good reason for a Resolution |
---|
| 1606 | + * Multiplier to have a count other than 1. |
---|
| 1607 | + * Ignore that case. |
---|
| 1608 | + */ |
---|
| 1609 | + if (report->field[i]->report_count != 1) |
---|
| 1610 | + continue; |
---|
| 1611 | + |
---|
| 1612 | + for (j = 0; j < report->field[i]->maxusage; j++) { |
---|
| 1613 | + usage = &report->field[i]->usage[j]; |
---|
| 1614 | + |
---|
| 1615 | + if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER) |
---|
| 1616 | + continue; |
---|
| 1617 | + |
---|
| 1618 | + /* |
---|
| 1619 | + * If we have more than one feature within this |
---|
| 1620 | + * report we need to fill in the bits from the |
---|
| 1621 | + * others before we can overwrite the ones for the |
---|
| 1622 | + * Resolution Multiplier. |
---|
| 1623 | + * |
---|
| 1624 | + * But if we're not allowed to read from the device, |
---|
| 1625 | + * we just bail. Such a device should not exist |
---|
| 1626 | + * anyway. |
---|
| 1627 | + */ |
---|
| 1628 | + if (!get_report_completed && report->maxfield > 1) { |
---|
| 1629 | + if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS) |
---|
| 1630 | + return update_needed; |
---|
| 1631 | + |
---|
| 1632 | + hid_hw_request(hid, report, HID_REQ_GET_REPORT); |
---|
| 1633 | + hid_hw_wait(hid); |
---|
| 1634 | + get_report_completed = true; |
---|
| 1635 | + } |
---|
| 1636 | + |
---|
| 1637 | + report->field[i]->value[j] = value; |
---|
| 1638 | + update_needed = true; |
---|
| 1639 | + } |
---|
| 1640 | + } |
---|
| 1641 | + |
---|
| 1642 | + return update_needed; |
---|
| 1643 | +} |
---|
| 1644 | + |
---|
| 1645 | +static void hidinput_change_resolution_multipliers(struct hid_device *hid) |
---|
| 1646 | +{ |
---|
| 1647 | + struct hid_report_enum *rep_enum; |
---|
| 1648 | + struct hid_report *rep; |
---|
| 1649 | + int ret; |
---|
| 1650 | + |
---|
| 1651 | + rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; |
---|
| 1652 | + list_for_each_entry(rep, &rep_enum->report_list, list) { |
---|
| 1653 | + bool update_needed = __hidinput_change_resolution_multipliers(hid, |
---|
| 1654 | + rep, true); |
---|
| 1655 | + |
---|
| 1656 | + if (update_needed) { |
---|
| 1657 | + ret = __hid_request(hid, rep, HID_REQ_SET_REPORT); |
---|
| 1658 | + if (ret) { |
---|
| 1659 | + __hidinput_change_resolution_multipliers(hid, |
---|
| 1660 | + rep, false); |
---|
| 1661 | + return; |
---|
| 1662 | + } |
---|
| 1663 | + } |
---|
| 1664 | + } |
---|
| 1665 | + |
---|
| 1666 | + /* refresh our structs */ |
---|
| 1667 | + hid_setup_resolution_multiplier(hid); |
---|
| 1668 | +} |
---|
| 1669 | + |
---|
1526 | 1670 | static void report_features(struct hid_device *hid) |
---|
1527 | 1671 | { |
---|
1528 | 1672 | struct hid_driver *drv = hid->driver; |
---|
.. | .. |
---|
1558 | 1702 | struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); |
---|
1559 | 1703 | struct input_dev *input_dev = input_allocate_device(); |
---|
1560 | 1704 | const char *suffix = NULL; |
---|
| 1705 | + size_t suffix_len, name_len; |
---|
1561 | 1706 | |
---|
1562 | 1707 | if (!hidinput || !input_dev) |
---|
1563 | 1708 | goto fail; |
---|
.. | .. |
---|
1601 | 1746 | } |
---|
1602 | 1747 | |
---|
1603 | 1748 | if (suffix) { |
---|
1604 | | - hidinput->name = kasprintf(GFP_KERNEL, "%s %s", |
---|
1605 | | - hid->name, suffix); |
---|
1606 | | - if (!hidinput->name) |
---|
1607 | | - goto fail; |
---|
| 1749 | + name_len = strlen(hid->name); |
---|
| 1750 | + suffix_len = strlen(suffix); |
---|
| 1751 | + if ((name_len < suffix_len) || |
---|
| 1752 | + strcmp(hid->name + name_len - suffix_len, suffix)) { |
---|
| 1753 | + hidinput->name = kasprintf(GFP_KERNEL, "%s %s", |
---|
| 1754 | + hid->name, suffix); |
---|
| 1755 | + if (!hidinput->name) |
---|
| 1756 | + goto fail; |
---|
| 1757 | + } |
---|
1608 | 1758 | } |
---|
1609 | 1759 | |
---|
1610 | 1760 | input_set_drvdata(input_dev, hid); |
---|
.. | .. |
---|
1810 | 1960 | } |
---|
1811 | 1961 | } |
---|
1812 | 1962 | |
---|
| 1963 | + hidinput_change_resolution_multipliers(hid); |
---|
| 1964 | + |
---|
1813 | 1965 | list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { |
---|
1814 | 1966 | if (drv->input_configured && |
---|
1815 | 1967 | drv->input_configured(hid, hidinput)) |
---|
.. | .. |
---|
1868 | 2020 | cancel_work_sync(&hid->led_work); |
---|
1869 | 2021 | } |
---|
1870 | 2022 | EXPORT_SYMBOL_GPL(hidinput_disconnect); |
---|
1871 | | - |
---|