diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-05 20:53:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-05 20:53:40 -0500 |
commit | cf26057a9441173ad552e90cea3344607075c9ad (patch) | |
tree | 52410b934b7270e49df1917c2534cc40e30664bc | |
parent | 1686cc1a31f45a3fd090e5d0c6fce777422e13fa (diff) | |
parent | bd8879faafe6d057237461c4d58d8b0d37b9e3ee (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID updates from Jiri Kosina:
- high-resolution scrolling support that gracefully handles differences
between MS and Logitech implementations in HW, from Peter Hutterer
and Harry Cutts
- MSI IRQ support for intel-ish driver, from Song Hongyan
- support for new hardware (Cougar 700K, Odys Winbook 13, ASUS FX503VD,
ASUS T101HA) from Daniel M. Lambea, Hans de Goede and Aleix Roca
Nonell
- other small assorted fixups
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (22 commits)
HID: i2c-hid: Add Odys Winbook 13 to descriptor override
HID: lenovo: Add checks to fix of_led_classdev_register
HID: intel-ish-hid: add MSI interrupt support
HID: debug: Change to use DEFINE_SHOW_ATTRIBUTE macro
HID: doc: fix wrong data structure reference for UHID_OUTPUT
HID: intel-ish-hid: fixes incorrect error handling
HID: asus: Add support for the ASUS T101HA keyboard dock
HID: logitech: Use LDJ_DEVICE macro for existing Logitech mice
HID: logitech: Enable high-resolution scrolling on Logitech mice
HID: logitech: Add function to enable HID++ 1.0 "scrolling acceleration"
HID: logitech-hidpp: fix typo, hiddpp to hidpp
HID: input: use the Resolution Multiplier for high-resolution scrolling
HID: core: process the Resolution Multiplier
HID: core: store the collections as a basic tree
Input: add `REL_WHEEL_HI_RES` and `REL_HWHEEL_HI_RES`
HID: input: support Microsoft wireless radio control hotkey
HID: use macros in IS_INPUT_APPLICATION
HID: asus: Add support for the ASUS FX503VD laptop
HID: asus: Add event handler to catch unmapped Asus Vendor UsagePage codes
HID: cougar: Add support for Cougar 700K Gaming Keyboard
...
-rw-r--r-- | Documentation/hid/uhid.txt | 2 | ||||
-rw-r--r-- | Documentation/input/event-codes.rst | 21 | ||||
-rw-r--r-- | drivers/hid/hid-asus.c | 28 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 174 | ||||
-rw-r--r-- | drivers/hid/hid-cougar.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-debug.c | 12 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 3 | ||||
-rw-r--r-- | drivers/hid/hid-input.c | 108 | ||||
-rw-r--r-- | drivers/hid/hid-lenovo.c | 10 | ||||
-rw-r--r-- | drivers/hid/hid-logitech-hidpp.c | 375 | ||||
-rw-r--r-- | drivers/hid/hidraw.c | 8 | ||||
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | 8 | ||||
-rw-r--r-- | drivers/hid/intel-ish-hid/ipc/pci-ish.c | 7 | ||||
-rw-r--r-- | drivers/hid/intel-ish-hid/ishtp-hid.c | 2 | ||||
-rw-r--r-- | include/linux/hid.h | 17 | ||||
-rw-r--r-- | include/uapi/linux/input-event-codes.h | 2 | ||||
-rw-r--r-- | samples/hidraw/hid-example.c | 2 |
17 files changed, 720 insertions, 61 deletions
diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt index c8656dd029a9..958fff945304 100644 --- a/Documentation/hid/uhid.txt +++ b/Documentation/hid/uhid.txt | |||
@@ -160,7 +160,7 @@ them but you should handle them according to your needs. | |||
160 | UHID_OUTPUT: | 160 | UHID_OUTPUT: |
161 | This is sent if the HID device driver wants to send raw data to the I/O | 161 | This is sent if the HID device driver wants to send raw data to the I/O |
162 | device on the interrupt channel. You should read the payload and forward it to | 162 | device on the interrupt channel. You should read the payload and forward it to |
163 | the device. The payload is of type "struct uhid_data_req". | 163 | the device. The payload is of type "struct uhid_output_req". |
164 | This may be received even though you haven't received UHID_OPEN, yet. | 164 | This may be received even though you haven't received UHID_OPEN, yet. |
165 | 165 | ||
166 | UHID_GET_REPORT: | 166 | UHID_GET_REPORT: |
diff --git a/Documentation/input/event-codes.rst b/Documentation/input/event-codes.rst index a8c0873beb95..b24b5343f5eb 100644 --- a/Documentation/input/event-codes.rst +++ b/Documentation/input/event-codes.rst | |||
@@ -190,7 +190,26 @@ A few EV_REL codes have special meanings: | |||
190 | * REL_WHEEL, REL_HWHEEL: | 190 | * REL_WHEEL, REL_HWHEEL: |
191 | 191 | ||
192 | - These codes are used for vertical and horizontal scroll wheels, | 192 | - These codes are used for vertical and horizontal scroll wheels, |
193 | respectively. | 193 | respectively. The value is the number of detents moved on the wheel, the |
194 | physical size of which varies by device. For high-resolution wheels | ||
195 | this may be an approximation based on the high-resolution scroll events, | ||
196 | see REL_WHEEL_HI_RES. These event codes are legacy codes and | ||
197 | REL_WHEEL_HI_RES and REL_HWHEEL_HI_RES should be preferred where | ||
198 | available. | ||
199 | |||
200 | * REL_WHEEL_HI_RES, REL_HWHEEL_HI_RES: | ||
201 | |||
202 | - High-resolution scroll wheel data. The accumulated value 120 represents | ||
203 | movement by one detent. For devices that do not provide high-resolution | ||
204 | scrolling, the value is always a multiple of 120. For devices with | ||
205 | high-resolution scrolling, the value may be a fraction of 120. | ||
206 | |||
207 | If a vertical scroll wheel supports high-resolution scrolling, this code | ||
208 | will be emitted in addition to REL_WHEEL or REL_HWHEEL. The REL_WHEEL | ||
209 | and REL_HWHEEL may be an approximation based on the high-resolution | ||
210 | scroll events. There is no guarantee that the high-resolution data | ||
211 | is a multiple of 120 at the time of an emulated REL_WHEEL or REL_HWHEEL | ||
212 | event. | ||
194 | 213 | ||
195 | EV_ABS | 214 | EV_ABS |
196 | ------ | 215 | ------ |
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index a1fa2fc8c9b5..951bb17ae8b2 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c | |||
@@ -70,6 +70,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); | |||
70 | #define QUIRK_T100_KEYBOARD BIT(6) | 70 | #define QUIRK_T100_KEYBOARD BIT(6) |
71 | #define QUIRK_T100CHI BIT(7) | 71 | #define QUIRK_T100CHI BIT(7) |
72 | #define QUIRK_G752_KEYBOARD BIT(8) | 72 | #define QUIRK_G752_KEYBOARD BIT(8) |
73 | #define QUIRK_T101HA_DOCK BIT(9) | ||
73 | 74 | ||
74 | #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ | 75 | #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ |
75 | QUIRK_NO_INIT_REPORTS | \ | 76 | QUIRK_NO_INIT_REPORTS | \ |
@@ -241,6 +242,18 @@ static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size) | |||
241 | return 1; | 242 | return 1; |
242 | } | 243 | } |
243 | 244 | ||
245 | static int asus_event(struct hid_device *hdev, struct hid_field *field, | ||
246 | struct hid_usage *usage, __s32 value) | ||
247 | { | ||
248 | if ((usage->hid & HID_USAGE_PAGE) == 0xff310000 && | ||
249 | (usage->hid & HID_USAGE) != 0x00 && !usage->type) { | ||
250 | hid_warn(hdev, "Unmapped Asus vendor usagepage code 0x%02x\n", | ||
251 | usage->hid & HID_USAGE); | ||
252 | } | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
244 | static int asus_raw_event(struct hid_device *hdev, | 257 | static int asus_raw_event(struct hid_device *hdev, |
245 | struct hid_report *report, u8 *data, int size) | 258 | struct hid_report *report, u8 *data, int size) |
246 | { | 259 | { |
@@ -510,6 +523,7 @@ static int asus_input_mapping(struct hid_device *hdev, | |||
510 | case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break; | 523 | case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break; |
511 | case 0x35: asus_map_key_clear(KEY_DISPLAY_OFF); break; | 524 | case 0x35: asus_map_key_clear(KEY_DISPLAY_OFF); break; |
512 | case 0x6c: asus_map_key_clear(KEY_SLEEP); break; | 525 | case 0x6c: asus_map_key_clear(KEY_SLEEP); break; |
526 | case 0x7c: asus_map_key_clear(KEY_MICMUTE); break; | ||
513 | case 0x82: asus_map_key_clear(KEY_CAMERA); break; | 527 | case 0x82: asus_map_key_clear(KEY_CAMERA); break; |
514 | case 0x88: asus_map_key_clear(KEY_RFKILL); break; | 528 | case 0x88: asus_map_key_clear(KEY_RFKILL); break; |
515 | case 0xb5: asus_map_key_clear(KEY_CALC); break; | 529 | case 0xb5: asus_map_key_clear(KEY_CALC); break; |
@@ -528,6 +542,9 @@ static int asus_input_mapping(struct hid_device *hdev, | |||
528 | /* Fn+Space Power4Gear Hybrid */ | 542 | /* Fn+Space Power4Gear Hybrid */ |
529 | case 0x5c: asus_map_key_clear(KEY_PROG3); break; | 543 | case 0x5c: asus_map_key_clear(KEY_PROG3); break; |
530 | 544 | ||
545 | /* Fn+F5 "fan" symbol on FX503VD */ | ||
546 | case 0x99: asus_map_key_clear(KEY_PROG4); break; | ||
547 | |||
531 | default: | 548 | default: |
532 | /* ASUS lazily declares 256 usages, ignore the rest, | 549 | /* ASUS lazily declares 256 usages, ignore the rest, |
533 | * as some make the keyboard appear as a pointer device. */ | 550 | * as some make the keyboard appear as a pointer device. */ |
@@ -683,6 +700,11 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
683 | return ret; | 700 | return ret; |
684 | } | 701 | } |
685 | 702 | ||
703 | /* use hid-multitouch for T101HA touchpad */ | ||
704 | if (id->driver_data & QUIRK_T101HA_DOCK && | ||
705 | hdev->collection->usage == HID_GD_MOUSE) | ||
706 | return -ENODEV; | ||
707 | |||
686 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | 708 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
687 | if (ret) { | 709 | if (ret) { |
688 | hid_err(hdev, "Asus hw start failed: %d\n", ret); | 710 | hid_err(hdev, "Asus hw start failed: %d\n", ret); |
@@ -806,11 +828,16 @@ static const struct hid_device_id asus_devices[] = { | |||
806 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, | 828 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
807 | USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3), QUIRK_G752_KEYBOARD }, | 829 | USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3), QUIRK_G752_KEYBOARD }, |
808 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, | 830 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
831 | USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD), | ||
832 | QUIRK_USE_KBD_BACKLIGHT }, | ||
833 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, | ||
809 | USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD), | 834 | USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD), |
810 | QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES }, | 835 | QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES }, |
811 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, | 836 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
812 | USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD), | 837 | USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD), |
813 | QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES }, | 838 | QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES }, |
839 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, | ||
840 | USB_DEVICE_ID_ASUSTEK_T101HA_KEYBOARD), QUIRK_T101HA_DOCK }, | ||
814 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) }, | 841 | { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) }, |
815 | { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) }, | 842 | { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) }, |
816 | { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) }, | 843 | { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) }, |
@@ -832,6 +859,7 @@ static struct hid_driver asus_driver = { | |||
832 | #ifdef CONFIG_PM | 859 | #ifdef CONFIG_PM |
833 | .reset_resume = asus_reset_resume, | 860 | .reset_resume = asus_reset_resume, |
834 | #endif | 861 | #endif |
862 | .event = asus_event, | ||
835 | .raw_event = asus_raw_event | 863 | .raw_event = asus_raw_event |
836 | }; | 864 | }; |
837 | module_hid_driver(asus_driver); | 865 | module_hid_driver(asus_driver); |
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5bec9244c45b..f41d5fe51abe 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -172,6 +172,8 @@ static int open_collection(struct hid_parser *parser, unsigned type) | |||
172 | collection->type = type; | 172 | collection->type = type; |
173 | collection->usage = usage; | 173 | collection->usage = usage; |
174 | collection->level = parser->collection_stack_ptr - 1; | 174 | collection->level = parser->collection_stack_ptr - 1; |
175 | collection->parent = parser->active_collection; | ||
176 | parser->active_collection = collection; | ||
175 | 177 | ||
176 | if (type == HID_COLLECTION_APPLICATION) | 178 | if (type == HID_COLLECTION_APPLICATION) |
177 | parser->device->maxapplication++; | 179 | parser->device->maxapplication++; |
@@ -190,6 +192,8 @@ static int close_collection(struct hid_parser *parser) | |||
190 | return -EINVAL; | 192 | return -EINVAL; |
191 | } | 193 | } |
192 | parser->collection_stack_ptr--; | 194 | parser->collection_stack_ptr--; |
195 | if (parser->active_collection) | ||
196 | parser->active_collection = parser->active_collection->parent; | ||
193 | return 0; | 197 | return 0; |
194 | } | 198 | } |
195 | 199 | ||
@@ -290,6 +294,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign | |||
290 | field->usage[i].collection_index = | 294 | field->usage[i].collection_index = |
291 | parser->local.collection_index[j]; | 295 | parser->local.collection_index[j]; |
292 | field->usage[i].usage_index = i; | 296 | field->usage[i].usage_index = i; |
297 | field->usage[i].resolution_multiplier = 1; | ||
293 | } | 298 | } |
294 | 299 | ||
295 | field->maxusage = usages; | 300 | field->maxusage = usages; |
@@ -943,6 +948,167 @@ struct hid_report *hid_validate_values(struct hid_device *hid, | |||
943 | } | 948 | } |
944 | EXPORT_SYMBOL_GPL(hid_validate_values); | 949 | EXPORT_SYMBOL_GPL(hid_validate_values); |
945 | 950 | ||
951 | static int hid_calculate_multiplier(struct hid_device *hid, | ||
952 | struct hid_field *multiplier) | ||
953 | { | ||
954 | int m; | ||
955 | __s32 v = *multiplier->value; | ||
956 | __s32 lmin = multiplier->logical_minimum; | ||
957 | __s32 lmax = multiplier->logical_maximum; | ||
958 | __s32 pmin = multiplier->physical_minimum; | ||
959 | __s32 pmax = multiplier->physical_maximum; | ||
960 | |||
961 | /* | ||
962 | * "Because OS implementations will generally divide the control's | ||
963 | * reported count by the Effective Resolution Multiplier, designers | ||
964 | * should take care not to establish a potential Effective | ||
965 | * Resolution Multiplier of zero." | ||
966 | * HID Usage Table, v1.12, Section 4.3.1, p31 | ||
967 | */ | ||
968 | if (lmax - lmin == 0) | ||
969 | return 1; | ||
970 | /* | ||
971 | * Handling the unit exponent is left as an exercise to whoever | ||
972 | * finds a device where that exponent is not 0. | ||
973 | */ | ||
974 | m = ((v - lmin)/(lmax - lmin) * (pmax - pmin) + pmin); | ||
975 | if (unlikely(multiplier->unit_exponent != 0)) { | ||
976 | hid_warn(hid, | ||
977 | "unsupported Resolution Multiplier unit exponent %d\n", | ||
978 | multiplier->unit_exponent); | ||
979 | } | ||
980 | |||
981 | /* There are no devices with an effective multiplier > 255 */ | ||
982 | if (unlikely(m == 0 || m > 255 || m < -255)) { | ||
983 | hid_warn(hid, "unsupported Resolution Multiplier %d\n", m); | ||
984 | m = 1; | ||
985 | } | ||
986 | |||
987 | return m; | ||
988 | } | ||
989 | |||
990 | static void hid_apply_multiplier_to_field(struct hid_device *hid, | ||
991 | struct hid_field *field, | ||
992 | struct hid_collection *multiplier_collection, | ||
993 | int effective_multiplier) | ||
994 | { | ||
995 | struct hid_collection *collection; | ||
996 | struct hid_usage *usage; | ||
997 | int i; | ||
998 | |||
999 | /* | ||
1000 | * If multiplier_collection is NULL, the multiplier applies | ||
1001 | * to all fields in the report. | ||
1002 | * Otherwise, it is the Logical Collection the multiplier applies to | ||
1003 | * but our field may be in a subcollection of that collection. | ||
1004 | */ | ||
1005 | for (i = 0; i < field->maxusage; i++) { | ||
1006 | usage = &field->usage[i]; | ||
1007 | |||
1008 | collection = &hid->collection[usage->collection_index]; | ||
1009 | while (collection && collection != multiplier_collection) | ||
1010 | collection = collection->parent; | ||
1011 | |||
1012 | if (collection || multiplier_collection == NULL) | ||
1013 | usage->resolution_multiplier = effective_multiplier; | ||
1014 | |||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | static void hid_apply_multiplier(struct hid_device *hid, | ||
1019 | struct hid_field *multiplier) | ||
1020 | { | ||
1021 | struct hid_report_enum *rep_enum; | ||
1022 | struct hid_report *rep; | ||
1023 | struct hid_field *field; | ||
1024 | struct hid_collection *multiplier_collection; | ||
1025 | int effective_multiplier; | ||
1026 | int i; | ||
1027 | |||
1028 | /* | ||
1029 | * "The Resolution Multiplier control must be contained in the same | ||
1030 | * Logical Collection as the control(s) to which it is to be applied. | ||
1031 | * If no Resolution Multiplier is defined, then the Resolution | ||
1032 | * Multiplier defaults to 1. If more than one control exists in a | ||
1033 | * Logical Collection, the Resolution Multiplier is associated with | ||
1034 | * all controls in the collection. If no Logical Collection is | ||
1035 | * defined, the Resolution Multiplier is associated with all | ||
1036 | * controls in the report." | ||
1037 | * HID Usage Table, v1.12, Section 4.3.1, p30 | ||
1038 | * | ||
1039 | * Thus, search from the current collection upwards until we find a | ||
1040 | * logical collection. Then search all fields for that same parent | ||
1041 | * collection. Those are the fields the multiplier applies to. | ||
1042 | * | ||
1043 | * If we have more than one multiplier, it will overwrite the | ||
1044 | * applicable fields later. | ||
1045 | */ | ||
1046 | multiplier_collection = &hid->collection[multiplier->usage->collection_index]; | ||
1047 | while (multiplier_collection && | ||
1048 | multiplier_collection->type != HID_COLLECTION_LOGICAL) | ||
1049 | multiplier_collection = multiplier_collection->parent; | ||
1050 | |||
1051 | effective_multiplier = hid_calculate_multiplier(hid, multiplier); | ||
1052 | |||
1053 | rep_enum = &hid->report_enum[HID_INPUT_REPORT]; | ||
1054 | list_for_each_entry(rep, &rep_enum->report_list, list) { | ||
1055 | for (i = 0; i < rep->maxfield; i++) { | ||
1056 | field = rep->field[i]; | ||
1057 | hid_apply_multiplier_to_field(hid, field, | ||
1058 | multiplier_collection, | ||
1059 | effective_multiplier); | ||
1060 | } | ||
1061 | } | ||
1062 | } | ||
1063 | |||
1064 | /* | ||
1065 | * hid_setup_resolution_multiplier - set up all resolution multipliers | ||
1066 | * | ||
1067 | * @device: hid device | ||
1068 | * | ||
1069 | * Search for all Resolution Multiplier Feature Reports and apply their | ||
1070 | * value to all matching Input items. This only updates the internal struct | ||
1071 | * fields. | ||
1072 | * | ||
1073 | * The Resolution Multiplier is applied by the hardware. If the multiplier | ||
1074 | * is anything other than 1, the hardware will send pre-multiplied events | ||
1075 | * so that the same physical interaction generates an accumulated | ||
1076 | * accumulated_value = value * * multiplier | ||
1077 | * This may be achieved by sending | ||
1078 | * - "value * multiplier" for each event, or | ||
1079 | * - "value" but "multiplier" times as frequently, or | ||
1080 | * - a combination of the above | ||
1081 | * The only guarantee is that the same physical interaction always generates | ||
1082 | * an accumulated 'value * multiplier'. | ||
1083 | * | ||
1084 | * This function must be called before any event processing and after | ||
1085 | * any SetRequest to the Resolution Multiplier. | ||
1086 | */ | ||
1087 | void hid_setup_resolution_multiplier(struct hid_device *hid) | ||
1088 | { | ||
1089 | struct hid_report_enum *rep_enum; | ||
1090 | struct hid_report *rep; | ||
1091 | struct hid_usage *usage; | ||
1092 | int i, j; | ||
1093 | |||
1094 | rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; | ||
1095 | list_for_each_entry(rep, &rep_enum->report_list, list) { | ||
1096 | for (i = 0; i < rep->maxfield; i++) { | ||
1097 | /* Ignore if report count is out of bounds. */ | ||
1098 | if (rep->field[i]->report_count < 1) | ||
1099 | continue; | ||
1100 | |||
1101 | for (j = 0; j < rep->field[i]->maxusage; j++) { | ||
1102 | usage = &rep->field[i]->usage[j]; | ||
1103 | if (usage->hid == HID_GD_RESOLUTION_MULTIPLIER) | ||
1104 | hid_apply_multiplier(hid, | ||
1105 | rep->field[i]); | ||
1106 | } | ||
1107 | } | ||
1108 | } | ||
1109 | } | ||
1110 | EXPORT_SYMBOL_GPL(hid_setup_resolution_multiplier); | ||
1111 | |||
946 | /** | 1112 | /** |
947 | * hid_open_report - open a driver-specific device report | 1113 | * hid_open_report - open a driver-specific device report |
948 | * | 1114 | * |
@@ -1039,9 +1205,17 @@ int hid_open_report(struct hid_device *device) | |||
1039 | hid_err(device, "unbalanced delimiter at end of report description\n"); | 1205 | hid_err(device, "unbalanced delimiter at end of report description\n"); |
1040 | goto err; | 1206 | goto err; |
1041 | } | 1207 | } |
1208 | |||
1209 | /* | ||
1210 | * fetch initial values in case the device's | ||
1211 | * default multiplier isn't the recommended 1 | ||
1212 | */ | ||
1213 | hid_setup_resolution_multiplier(device); | ||
1214 | |||
1042 | kfree(parser->collection_stack); | 1215 | kfree(parser->collection_stack); |
1043 | vfree(parser); | 1216 | vfree(parser); |
1044 | device->status |= HID_STAT_PARSED; | 1217 | device->status |= HID_STAT_PARSED; |
1218 | |||
1045 | return 0; | 1219 | return 0; |
1046 | } | 1220 | } |
1047 | } | 1221 | } |
diff --git a/drivers/hid/hid-cougar.c b/drivers/hid/hid-cougar.c index 3f0916b64c60..e0bb7b34f3a4 100644 --- a/drivers/hid/hid-cougar.c +++ b/drivers/hid/hid-cougar.c | |||
@@ -326,6 +326,8 @@ module_param_cb(g6_is_space, &cougar_g6_is_space_ops, &g6_is_space, 0644); | |||
326 | static struct hid_device_id cougar_id_table[] = { | 326 | static struct hid_device_id cougar_id_table[] = { |
327 | { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR, | 327 | { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR, |
328 | USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) }, | 328 | USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) }, |
329 | { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR, | ||
330 | USB_DEVICE_ID_COUGAR_700K_GAMING_KEYBOARD) }, | ||
329 | {} | 331 | {} |
330 | }; | 332 | }; |
331 | MODULE_DEVICE_TABLE(hid, cougar_id_table); | 333 | MODULE_DEVICE_TABLE(hid, cougar_id_table); |
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index b48100236df8..c530476edba6 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c | |||
@@ -1072,11 +1072,6 @@ static int hid_debug_rdesc_show(struct seq_file *f, void *p) | |||
1072 | return 0; | 1072 | return 0; |
1073 | } | 1073 | } |
1074 | 1074 | ||
1075 | static int hid_debug_rdesc_open(struct inode *inode, struct file *file) | ||
1076 | { | ||
1077 | return single_open(file, hid_debug_rdesc_show, inode->i_private); | ||
1078 | } | ||
1079 | |||
1080 | static int hid_debug_events_open(struct inode *inode, struct file *file) | 1075 | static int hid_debug_events_open(struct inode *inode, struct file *file) |
1081 | { | 1076 | { |
1082 | int err = 0; | 1077 | int err = 0; |
@@ -1211,12 +1206,7 @@ static int hid_debug_events_release(struct inode *inode, struct file *file) | |||
1211 | return 0; | 1206 | return 0; |
1212 | } | 1207 | } |
1213 | 1208 | ||
1214 | static const struct file_operations hid_debug_rdesc_fops = { | 1209 | DEFINE_SHOW_ATTRIBUTE(hid_debug_rdesc); |
1215 | .open = hid_debug_rdesc_open, | ||
1216 | .read = seq_read, | ||
1217 | .llseek = seq_lseek, | ||
1218 | .release = single_release, | ||
1219 | }; | ||
1220 | 1210 | ||
1221 | static const struct file_operations hid_debug_events_fops = { | 1211 | static const struct file_operations hid_debug_events_fops = { |
1222 | .owner = THIS_MODULE, | 1212 | .owner = THIS_MODULE, |
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 27519eb8ee63..518fa76414f5 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h | |||
@@ -187,12 +187,14 @@ | |||
187 | #define USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD 0x17e0 | 187 | #define USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD 0x17e0 |
188 | #define USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD 0x1807 | 188 | #define USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD 0x1807 |
189 | #define USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD 0x8502 | 189 | #define USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD 0x8502 |
190 | #define USB_DEVICE_ID_ASUSTEK_T101HA_KEYBOARD 0x183d | ||
190 | #define USB_DEVICE_ID_ASUSTEK_T304_KEYBOARD 0x184a | 191 | #define USB_DEVICE_ID_ASUSTEK_T304_KEYBOARD 0x184a |
191 | #define USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD 0x8585 | 192 | #define USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD 0x8585 |
192 | #define USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD 0x0101 | 193 | #define USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD 0x0101 |
193 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854 | 194 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854 |
194 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837 | 195 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837 |
195 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822 | 196 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822 |
197 | #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 | ||
196 | 198 | ||
197 | #define USB_VENDOR_ID_ATEN 0x0557 | 199 | #define USB_VENDOR_ID_ATEN 0x0557 |
198 | #define USB_DEVICE_ID_ATEN_UC100KM 0x2004 | 200 | #define USB_DEVICE_ID_ATEN_UC100KM 0x2004 |
@@ -1025,6 +1027,7 @@ | |||
1025 | 1027 | ||
1026 | #define USB_VENDOR_ID_SOLID_YEAR 0x060b | 1028 | #define USB_VENDOR_ID_SOLID_YEAR 0x060b |
1027 | #define USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD 0x500a | 1029 | #define USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD 0x500a |
1030 | #define USB_DEVICE_ID_COUGAR_700K_GAMING_KEYBOARD 0x700a | ||
1028 | 1031 | ||
1029 | #define USB_VENDOR_ID_SOUNDGRAPH 0x15c2 | 1032 | #define USB_VENDOR_ID_SOUNDGRAPH 0x15c2 |
1030 | #define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034 | 1033 | #define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034 |
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index d6fab5798487..59a5608b8dc0 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
@@ -712,7 +712,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
712 | map_abs_clear(usage->hid & 0xf); | 712 | map_abs_clear(usage->hid & 0xf); |
713 | break; | 713 | break; |
714 | 714 | ||
715 | case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: | 715 | case HID_GD_WHEEL: |
716 | if (field->flags & HID_MAIN_ITEM_RELATIVE) { | ||
717 | set_bit(REL_WHEEL, input->relbit); | ||
718 | map_rel(REL_WHEEL_HI_RES); | ||
719 | } else { | ||
720 | map_abs(usage->hid & 0xf); | ||
721 | } | ||
722 | break; | ||
723 | case HID_GD_SLIDER: case HID_GD_DIAL: | ||
716 | if (field->flags & HID_MAIN_ITEM_RELATIVE) | 724 | if (field->flags & HID_MAIN_ITEM_RELATIVE) |
717 | map_rel(usage->hid & 0xf); | 725 | map_rel(usage->hid & 0xf); |
718 | else | 726 | else |
@@ -1012,7 +1020,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
1012 | case 0x22f: map_key_clear(KEY_ZOOMRESET); break; | 1020 | case 0x22f: map_key_clear(KEY_ZOOMRESET); break; |
1013 | case 0x233: map_key_clear(KEY_SCROLLUP); break; | 1021 | case 0x233: map_key_clear(KEY_SCROLLUP); break; |
1014 | case 0x234: map_key_clear(KEY_SCROLLDOWN); break; | 1022 | case 0x234: map_key_clear(KEY_SCROLLDOWN); break; |
1015 | case 0x238: map_rel(REL_HWHEEL); break; | 1023 | case 0x238: /* AC Pan */ |
1024 | set_bit(REL_HWHEEL, input->relbit); | ||
1025 | map_rel(REL_HWHEEL_HI_RES); | ||
1026 | break; | ||
1016 | case 0x23d: map_key_clear(KEY_EDIT); break; | 1027 | case 0x23d: map_key_clear(KEY_EDIT); break; |
1017 | case 0x25f: map_key_clear(KEY_CANCEL); break; | 1028 | case 0x25f: map_key_clear(KEY_CANCEL); break; |
1018 | case 0x269: map_key_clear(KEY_INSERT); break; | 1029 | case 0x269: map_key_clear(KEY_INSERT); break; |
@@ -1200,6 +1211,38 @@ ignore: | |||
1200 | 1211 | ||
1201 | } | 1212 | } |
1202 | 1213 | ||
1214 | static void hidinput_handle_scroll(struct hid_usage *usage, | ||
1215 | struct input_dev *input, | ||
1216 | __s32 value) | ||
1217 | { | ||
1218 | int code; | ||
1219 | int hi_res, lo_res; | ||
1220 | |||
1221 | if (value == 0) | ||
1222 | return; | ||
1223 | |||
1224 | if (usage->code == REL_WHEEL_HI_RES) | ||
1225 | code = REL_WHEEL; | ||
1226 | else | ||
1227 | code = REL_HWHEEL; | ||
1228 | |||
1229 | /* | ||
1230 | * Windows reports one wheel click as value 120. Where a high-res | ||
1231 | * scroll wheel is present, a fraction of 120 is reported instead. | ||
1232 | * Our REL_WHEEL_HI_RES axis does the same because all HW must | ||
1233 | * adhere to the 120 expectation. | ||
1234 | */ | ||
1235 | hi_res = value * 120/usage->resolution_multiplier; | ||
1236 | |||
1237 | usage->wheel_accumulated += hi_res; | ||
1238 | lo_res = usage->wheel_accumulated/120; | ||
1239 | if (lo_res) | ||
1240 | usage->wheel_accumulated -= lo_res * 120; | ||
1241 | |||
1242 | input_event(input, EV_REL, code, lo_res); | ||
1243 | input_event(input, EV_REL, usage->code, hi_res); | ||
1244 | } | ||
1245 | |||
1203 | void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) | 1246 | void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) |
1204 | { | 1247 | { |
1205 | struct input_dev *input; | 1248 | struct input_dev *input; |
@@ -1262,6 +1305,12 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct | |||
1262 | if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ | 1305 | if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ |
1263 | return; | 1306 | return; |
1264 | 1307 | ||
1308 | if ((usage->type == EV_REL) && (usage->code == REL_WHEEL_HI_RES || | ||
1309 | usage->code == REL_HWHEEL_HI_RES)) { | ||
1310 | hidinput_handle_scroll(usage, input, value); | ||
1311 | return; | ||
1312 | } | ||
1313 | |||
1265 | if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) && | 1314 | if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) && |
1266 | (usage->code == ABS_VOLUME)) { | 1315 | (usage->code == ABS_VOLUME)) { |
1267 | int count = abs(value); | 1316 | int count = abs(value); |
@@ -1489,6 +1538,58 @@ static void hidinput_close(struct input_dev *dev) | |||
1489 | hid_hw_close(hid); | 1538 | hid_hw_close(hid); |
1490 | } | 1539 | } |
1491 | 1540 | ||
1541 | static void hidinput_change_resolution_multipliers(struct hid_device *hid) | ||
1542 | { | ||
1543 | struct hid_report_enum *rep_enum; | ||
1544 | struct hid_report *rep; | ||
1545 | struct hid_usage *usage; | ||
1546 | int i, j; | ||
1547 | |||
1548 | rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; | ||
1549 | list_for_each_entry(rep, &rep_enum->report_list, list) { | ||
1550 | bool update_needed = false; | ||
1551 | |||
1552 | if (rep->maxfield == 0) | ||
1553 | continue; | ||
1554 | |||
1555 | /* | ||
1556 | * If we have more than one feature within this report we | ||
1557 | * need to fill in the bits from the others before we can | ||
1558 | * overwrite the ones for the Resolution Multiplier. | ||
1559 | */ | ||
1560 | if (rep->maxfield > 1) { | ||
1561 | hid_hw_request(hid, rep, HID_REQ_GET_REPORT); | ||
1562 | hid_hw_wait(hid); | ||
1563 | } | ||
1564 | |||
1565 | for (i = 0; i < rep->maxfield; i++) { | ||
1566 | __s32 logical_max = rep->field[i]->logical_maximum; | ||
1567 | |||
1568 | /* There is no good reason for a Resolution | ||
1569 | * Multiplier to have a count other than 1. | ||
1570 | * Ignore that case. | ||
1571 | */ | ||
1572 | if (rep->field[i]->report_count != 1) | ||
1573 | continue; | ||
1574 | |||
1575 | for (j = 0; j < rep->field[i]->maxusage; j++) { | ||
1576 | usage = &rep->field[i]->usage[j]; | ||
1577 | |||
1578 | if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER) | ||
1579 | continue; | ||
1580 | |||
1581 | *rep->field[i]->value = logical_max; | ||
1582 | update_needed = true; | ||
1583 | } | ||
1584 | } | ||
1585 | if (update_needed) | ||
1586 | hid_hw_request(hid, rep, HID_REQ_SET_REPORT); | ||
1587 | } | ||
1588 | |||
1589 | /* refresh our structs */ | ||
1590 | hid_setup_resolution_multiplier(hid); | ||
1591 | } | ||
1592 | |||
1492 | static void report_features(struct hid_device *hid) | 1593 | static void report_features(struct hid_device *hid) |
1493 | { | 1594 | { |
1494 | struct hid_driver *drv = hid->driver; | 1595 | struct hid_driver *drv = hid->driver; |
@@ -1782,6 +1883,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) | |||
1782 | } | 1883 | } |
1783 | } | 1884 | } |
1784 | 1885 | ||
1886 | hidinput_change_resolution_multipliers(hid); | ||
1887 | |||
1785 | list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { | 1888 | list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { |
1786 | if (drv->input_configured && | 1889 | if (drv->input_configured && |
1787 | drv->input_configured(hid, hidinput)) | 1890 | drv->input_configured(hid, hidinput)) |
@@ -1840,4 +1943,3 @@ void hidinput_disconnect(struct hid_device *hid) | |||
1840 | cancel_work_sync(&hid->led_work); | 1943 | cancel_work_sync(&hid->led_work); |
1841 | } | 1944 | } |
1842 | EXPORT_SYMBOL_GPL(hidinput_disconnect); | 1945 | EXPORT_SYMBOL_GPL(hidinput_disconnect); |
1843 | |||
diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 643b6eb54442..eacc76d2ab96 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c | |||
@@ -743,7 +743,9 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev) | |||
743 | data_pointer->led_mute.brightness_get = lenovo_led_brightness_get_tpkbd; | 743 | data_pointer->led_mute.brightness_get = lenovo_led_brightness_get_tpkbd; |
744 | data_pointer->led_mute.brightness_set = lenovo_led_brightness_set_tpkbd; | 744 | data_pointer->led_mute.brightness_set = lenovo_led_brightness_set_tpkbd; |
745 | data_pointer->led_mute.dev = dev; | 745 | data_pointer->led_mute.dev = dev; |
746 | led_classdev_register(dev, &data_pointer->led_mute); | 746 | ret = led_classdev_register(dev, &data_pointer->led_mute); |
747 | if (ret < 0) | ||
748 | goto err; | ||
747 | 749 | ||
748 | data_pointer->led_micmute.name = name_micmute; | 750 | data_pointer->led_micmute.name = name_micmute; |
749 | data_pointer->led_micmute.brightness_get = | 751 | data_pointer->led_micmute.brightness_get = |
@@ -751,7 +753,11 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev) | |||
751 | data_pointer->led_micmute.brightness_set = | 753 | data_pointer->led_micmute.brightness_set = |
752 | lenovo_led_brightness_set_tpkbd; | 754 | lenovo_led_brightness_set_tpkbd; |
753 | data_pointer->led_micmute.dev = dev; | 755 | data_pointer->led_micmute.dev = dev; |
754 | led_classdev_register(dev, &data_pointer->led_micmute); | 756 | ret = led_classdev_register(dev, &data_pointer->led_micmute); |
757 | if (ret < 0) { | ||
758 | led_classdev_unregister(&data_pointer->led_mute); | ||
759 | goto err; | ||
760 | } | ||
755 | 761 | ||
756 | lenovo_features_set_tpkbd(hdev); | 762 | lenovo_features_set_tpkbd(hdev); |
757 | 763 | ||
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 19cc980eebce..15ed6177a7a3 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
24 | #include <linux/sched/clock.h> | ||
24 | #include <linux/kfifo.h> | 25 | #include <linux/kfifo.h> |
25 | #include <linux/input/mt.h> | 26 | #include <linux/input/mt.h> |
26 | #include <linux/workqueue.h> | 27 | #include <linux/workqueue.h> |
@@ -64,6 +65,14 @@ MODULE_PARM_DESC(disable_tap_to_click, | |||
64 | #define HIDPP_QUIRK_NO_HIDINPUT BIT(23) | 65 | #define HIDPP_QUIRK_NO_HIDINPUT BIT(23) |
65 | #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) | 66 | #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) |
66 | #define HIDPP_QUIRK_UNIFYING BIT(25) | 67 | #define HIDPP_QUIRK_UNIFYING BIT(25) |
68 | #define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(26) | ||
69 | #define HIDPP_QUIRK_HI_RES_SCROLL_X2120 BIT(27) | ||
70 | #define HIDPP_QUIRK_HI_RES_SCROLL_X2121 BIT(28) | ||
71 | |||
72 | /* Convenience constant to check for any high-res support. */ | ||
73 | #define HIDPP_QUIRK_HI_RES_SCROLL (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \ | ||
74 | HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \ | ||
75 | HIDPP_QUIRK_HI_RES_SCROLL_X2121) | ||
67 | 76 | ||
68 | #define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT | 77 | #define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT |
69 | 78 | ||
@@ -128,6 +137,25 @@ struct hidpp_battery { | |||
128 | bool online; | 137 | bool online; |
129 | }; | 138 | }; |
130 | 139 | ||
140 | /** | ||
141 | * struct hidpp_scroll_counter - Utility class for processing high-resolution | ||
142 | * scroll events. | ||
143 | * @dev: the input device for which events should be reported. | ||
144 | * @wheel_multiplier: the scalar multiplier to be applied to each wheel event | ||
145 | * @remainder: counts the number of high-resolution units moved since the last | ||
146 | * low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should | ||
147 | * only be used by class methods. | ||
148 | * @direction: direction of last movement (1 or -1) | ||
149 | * @last_time: last event time, used to reset remainder after inactivity | ||
150 | */ | ||
151 | struct hidpp_scroll_counter { | ||
152 | struct input_dev *dev; | ||
153 | int wheel_multiplier; | ||
154 | int remainder; | ||
155 | int direction; | ||
156 | unsigned long long last_time; | ||
157 | }; | ||
158 | |||
131 | struct hidpp_device { | 159 | struct hidpp_device { |
132 | struct hid_device *hid_dev; | 160 | struct hid_device *hid_dev; |
133 | struct mutex send_mutex; | 161 | struct mutex send_mutex; |
@@ -149,6 +177,7 @@ struct hidpp_device { | |||
149 | unsigned long capabilities; | 177 | unsigned long capabilities; |
150 | 178 | ||
151 | struct hidpp_battery battery; | 179 | struct hidpp_battery battery; |
180 | struct hidpp_scroll_counter vertical_wheel_counter; | ||
152 | }; | 181 | }; |
153 | 182 | ||
154 | /* HID++ 1.0 error codes */ | 183 | /* HID++ 1.0 error codes */ |
@@ -391,6 +420,67 @@ static void hidpp_prefix_name(char **name, int name_length) | |||
391 | *name = new_name; | 420 | *name = new_name; |
392 | } | 421 | } |
393 | 422 | ||
423 | /** | ||
424 | * hidpp_scroll_counter_handle_scroll() - Send high- and low-resolution scroll | ||
425 | * events given a high-resolution wheel | ||
426 | * movement. | ||
427 | * @counter: a hid_scroll_counter struct describing the wheel. | ||
428 | * @hi_res_value: the movement of the wheel, in the mouse's high-resolution | ||
429 | * units. | ||
430 | * | ||
431 | * Given a high-resolution movement, this function converts the movement into | ||
432 | * fractions of 120 and emits high-resolution scroll events for the input | ||
433 | * device. It also uses the multiplier from &struct hid_scroll_counter to | ||
434 | * emit low-resolution scroll events when appropriate for | ||
435 | * backwards-compatibility with userspace input libraries. | ||
436 | */ | ||
437 | static void hidpp_scroll_counter_handle_scroll(struct hidpp_scroll_counter *counter, | ||
438 | int hi_res_value) | ||
439 | { | ||
440 | int low_res_value, remainder, direction; | ||
441 | unsigned long long now, previous; | ||
442 | |||
443 | hi_res_value = hi_res_value * 120/counter->wheel_multiplier; | ||
444 | input_report_rel(counter->dev, REL_WHEEL_HI_RES, hi_res_value); | ||
445 | |||
446 | remainder = counter->remainder; | ||
447 | direction = hi_res_value > 0 ? 1 : -1; | ||
448 | |||
449 | now = sched_clock(); | ||
450 | previous = counter->last_time; | ||
451 | counter->last_time = now; | ||
452 | /* | ||
453 | * Reset the remainder after a period of inactivity or when the | ||
454 | * direction changes. This prevents the REL_WHEEL emulation point | ||
455 | * from sliding for devices that don't always provide the same | ||
456 | * number of movements per detent. | ||
457 | */ | ||
458 | if (now - previous > 1000000000 || direction != counter->direction) | ||
459 | remainder = 0; | ||
460 | |||
461 | counter->direction = direction; | ||
462 | remainder += hi_res_value; | ||
463 | |||
464 | /* Some wheels will rest 7/8ths of a detent from the previous detent | ||
465 | * after slow movement, so we want the threshold for low-res events to | ||
466 | * be in the middle between two detents (e.g. after 4/8ths) as | ||
467 | * opposed to on the detents themselves (8/8ths). | ||
468 | */ | ||
469 | if (abs(remainder) >= 60) { | ||
470 | /* Add (or subtract) 1 because we want to trigger when the wheel | ||
471 | * is half-way to the next detent (i.e. scroll 1 detent after a | ||
472 | * 1/2 detent movement, 2 detents after a 1 1/2 detent movement, | ||
473 | * etc.). | ||
474 | */ | ||
475 | low_res_value = remainder / 120; | ||
476 | if (low_res_value == 0) | ||
477 | low_res_value = (hi_res_value > 0 ? 1 : -1); | ||
478 | input_report_rel(counter->dev, REL_WHEEL, low_res_value); | ||
479 | remainder -= low_res_value * 120; | ||
480 | } | ||
481 | counter->remainder = remainder; | ||
482 | } | ||
483 | |||
394 | /* -------------------------------------------------------------------------- */ | 484 | /* -------------------------------------------------------------------------- */ |
395 | /* HIDP++ 1.0 commands */ | 485 | /* HIDP++ 1.0 commands */ |
396 | /* -------------------------------------------------------------------------- */ | 486 | /* -------------------------------------------------------------------------- */ |
@@ -400,32 +490,53 @@ static void hidpp_prefix_name(char **name, int name_length) | |||
400 | #define HIDPP_SET_LONG_REGISTER 0x82 | 490 | #define HIDPP_SET_LONG_REGISTER 0x82 |
401 | #define HIDPP_GET_LONG_REGISTER 0x83 | 491 | #define HIDPP_GET_LONG_REGISTER 0x83 |
402 | 492 | ||
403 | #define HIDPP_REG_GENERAL 0x00 | 493 | /** |
404 | 494 | * hidpp10_set_register_bit() - Sets a single bit in a HID++ 1.0 register. | |
405 | static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev) | 495 | * @hidpp_dev: the device to set the register on. |
496 | * @register_address: the address of the register to modify. | ||
497 | * @byte: the byte of the register to modify. Should be less than 3. | ||
498 | * Return: 0 if successful, otherwise a negative error code. | ||
499 | */ | ||
500 | static int hidpp10_set_register_bit(struct hidpp_device *hidpp_dev, | ||
501 | u8 register_address, u8 byte, u8 bit) | ||
406 | { | 502 | { |
407 | struct hidpp_report response; | 503 | struct hidpp_report response; |
408 | int ret; | 504 | int ret; |
409 | u8 params[3] = { 0 }; | 505 | u8 params[3] = { 0 }; |
410 | 506 | ||
411 | ret = hidpp_send_rap_command_sync(hidpp_dev, | 507 | ret = hidpp_send_rap_command_sync(hidpp_dev, |
412 | REPORT_ID_HIDPP_SHORT, | 508 | REPORT_ID_HIDPP_SHORT, |
413 | HIDPP_GET_REGISTER, | 509 | HIDPP_GET_REGISTER, |
414 | HIDPP_REG_GENERAL, | 510 | register_address, |
415 | NULL, 0, &response); | 511 | NULL, 0, &response); |
416 | if (ret) | 512 | if (ret) |
417 | return ret; | 513 | return ret; |
418 | 514 | ||
419 | memcpy(params, response.rap.params, 3); | 515 | memcpy(params, response.rap.params, 3); |
420 | 516 | ||
421 | /* Set the battery bit */ | 517 | params[byte] |= BIT(bit); |
422 | params[0] |= BIT(4); | ||
423 | 518 | ||
424 | return hidpp_send_rap_command_sync(hidpp_dev, | 519 | return hidpp_send_rap_command_sync(hidpp_dev, |
425 | REPORT_ID_HIDPP_SHORT, | 520 | REPORT_ID_HIDPP_SHORT, |
426 | HIDPP_SET_REGISTER, | 521 | HIDPP_SET_REGISTER, |
427 | HIDPP_REG_GENERAL, | 522 | register_address, |
428 | params, 3, &response); | 523 | params, 3, &response); |
524 | } | ||
525 | |||
526 | |||
527 | #define HIDPP_REG_GENERAL 0x00 | ||
528 | |||
529 | static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev) | ||
530 | { | ||
531 | return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_GENERAL, 0, 4); | ||
532 | } | ||
533 | |||
534 | #define HIDPP_REG_FEATURES 0x01 | ||
535 | |||
536 | /* On HID++ 1.0 devices, high-res scroll was called "scrolling acceleration". */ | ||
537 | static int hidpp10_enable_scrolling_acceleration(struct hidpp_device *hidpp_dev) | ||
538 | { | ||
539 | return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_FEATURES, 0, 6); | ||
429 | } | 540 | } |
430 | 541 | ||
431 | #define HIDPP_REG_BATTERY_STATUS 0x07 | 542 | #define HIDPP_REG_BATTERY_STATUS 0x07 |
@@ -1137,6 +1248,99 @@ static int hidpp_battery_get_property(struct power_supply *psy, | |||
1137 | } | 1248 | } |
1138 | 1249 | ||
1139 | /* -------------------------------------------------------------------------- */ | 1250 | /* -------------------------------------------------------------------------- */ |
1251 | /* 0x2120: Hi-resolution scrolling */ | ||
1252 | /* -------------------------------------------------------------------------- */ | ||
1253 | |||
1254 | #define HIDPP_PAGE_HI_RESOLUTION_SCROLLING 0x2120 | ||
1255 | |||
1256 | #define CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE 0x10 | ||
1257 | |||
1258 | static int hidpp_hrs_set_highres_scrolling_mode(struct hidpp_device *hidpp, | ||
1259 | bool enabled, u8 *multiplier) | ||
1260 | { | ||
1261 | u8 feature_index; | ||
1262 | u8 feature_type; | ||
1263 | int ret; | ||
1264 | u8 params[1]; | ||
1265 | struct hidpp_report response; | ||
1266 | |||
1267 | ret = hidpp_root_get_feature(hidpp, | ||
1268 | HIDPP_PAGE_HI_RESOLUTION_SCROLLING, | ||
1269 | &feature_index, | ||
1270 | &feature_type); | ||
1271 | if (ret) | ||
1272 | return ret; | ||
1273 | |||
1274 | params[0] = enabled ? BIT(0) : 0; | ||
1275 | ret = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
1276 | CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE, | ||
1277 | params, sizeof(params), &response); | ||
1278 | if (ret) | ||
1279 | return ret; | ||
1280 | *multiplier = response.fap.params[1]; | ||
1281 | return 0; | ||
1282 | } | ||
1283 | |||
1284 | /* -------------------------------------------------------------------------- */ | ||
1285 | /* 0x2121: HiRes Wheel */ | ||
1286 | /* -------------------------------------------------------------------------- */ | ||
1287 | |||
1288 | #define HIDPP_PAGE_HIRES_WHEEL 0x2121 | ||
1289 | |||
1290 | #define CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY 0x00 | ||
1291 | #define CMD_HIRES_WHEEL_SET_WHEEL_MODE 0x20 | ||
1292 | |||
1293 | static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp, | ||
1294 | u8 *multiplier) | ||
1295 | { | ||
1296 | u8 feature_index; | ||
1297 | u8 feature_type; | ||
1298 | int ret; | ||
1299 | struct hidpp_report response; | ||
1300 | |||
1301 | ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, | ||
1302 | &feature_index, &feature_type); | ||
1303 | if (ret) | ||
1304 | goto return_default; | ||
1305 | |||
1306 | ret = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
1307 | CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY, | ||
1308 | NULL, 0, &response); | ||
1309 | if (ret) | ||
1310 | goto return_default; | ||
1311 | |||
1312 | *multiplier = response.fap.params[0]; | ||
1313 | return 0; | ||
1314 | return_default: | ||
1315 | hid_warn(hidpp->hid_dev, | ||
1316 | "Couldn't get wheel multiplier (error %d)\n", ret); | ||
1317 | return ret; | ||
1318 | } | ||
1319 | |||
1320 | static int hidpp_hrw_set_wheel_mode(struct hidpp_device *hidpp, bool invert, | ||
1321 | bool high_resolution, bool use_hidpp) | ||
1322 | { | ||
1323 | u8 feature_index; | ||
1324 | u8 feature_type; | ||
1325 | int ret; | ||
1326 | u8 params[1]; | ||
1327 | struct hidpp_report response; | ||
1328 | |||
1329 | ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, | ||
1330 | &feature_index, &feature_type); | ||
1331 | if (ret) | ||
1332 | return ret; | ||
1333 | |||
1334 | params[0] = (invert ? BIT(2) : 0) | | ||
1335 | (high_resolution ? BIT(1) : 0) | | ||
1336 | (use_hidpp ? BIT(0) : 0); | ||
1337 | |||
1338 | return hidpp_send_fap_command_sync(hidpp, feature_index, | ||
1339 | CMD_HIRES_WHEEL_SET_WHEEL_MODE, | ||
1340 | params, sizeof(params), &response); | ||
1341 | } | ||
1342 | |||
1343 | /* -------------------------------------------------------------------------- */ | ||
1140 | /* 0x4301: Solar Keyboard */ | 1344 | /* 0x4301: Solar Keyboard */ |
1141 | /* -------------------------------------------------------------------------- */ | 1345 | /* -------------------------------------------------------------------------- */ |
1142 | 1346 | ||
@@ -1465,7 +1669,7 @@ struct hidpp_ff_work_data { | |||
1465 | u8 size; | 1669 | u8 size; |
1466 | }; | 1670 | }; |
1467 | 1671 | ||
1468 | static const signed short hiddpp_ff_effects[] = { | 1672 | static const signed short hidpp_ff_effects[] = { |
1469 | FF_CONSTANT, | 1673 | FF_CONSTANT, |
1470 | FF_PERIODIC, | 1674 | FF_PERIODIC, |
1471 | FF_SINE, | 1675 | FF_SINE, |
@@ -1480,7 +1684,7 @@ static const signed short hiddpp_ff_effects[] = { | |||
1480 | -1 | 1684 | -1 |
1481 | }; | 1685 | }; |
1482 | 1686 | ||
1483 | static const signed short hiddpp_ff_effects_v2[] = { | 1687 | static const signed short hidpp_ff_effects_v2[] = { |
1484 | FF_RAMP, | 1688 | FF_RAMP, |
1485 | FF_FRICTION, | 1689 | FF_FRICTION, |
1486 | FF_INERTIA, | 1690 | FF_INERTIA, |
@@ -1873,11 +2077,11 @@ static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index) | |||
1873 | version = bcdDevice & 255; | 2077 | version = bcdDevice & 255; |
1874 | 2078 | ||
1875 | /* Set supported force feedback capabilities */ | 2079 | /* Set supported force feedback capabilities */ |
1876 | for (j = 0; hiddpp_ff_effects[j] >= 0; j++) | 2080 | for (j = 0; hidpp_ff_effects[j] >= 0; j++) |
1877 | set_bit(hiddpp_ff_effects[j], dev->ffbit); | 2081 | set_bit(hidpp_ff_effects[j], dev->ffbit); |
1878 | if (version > 1) | 2082 | if (version > 1) |
1879 | for (j = 0; hiddpp_ff_effects_v2[j] >= 0; j++) | 2083 | for (j = 0; hidpp_ff_effects_v2[j] >= 0; j++) |
1880 | set_bit(hiddpp_ff_effects_v2[j], dev->ffbit); | 2084 | set_bit(hidpp_ff_effects_v2[j], dev->ffbit); |
1881 | 2085 | ||
1882 | /* Read number of slots available in device */ | 2086 | /* Read number of slots available in device */ |
1883 | error = hidpp_send_fap_command_sync(hidpp, feature_index, | 2087 | error = hidpp_send_fap_command_sync(hidpp, feature_index, |
@@ -2387,10 +2591,15 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size) | |||
2387 | input_report_key(mydata->input, BTN_RIGHT, | 2591 | input_report_key(mydata->input, BTN_RIGHT, |
2388 | !!(data[1] & M560_MOUSE_BTN_RIGHT)); | 2592 | !!(data[1] & M560_MOUSE_BTN_RIGHT)); |
2389 | 2593 | ||
2390 | if (data[1] & M560_MOUSE_BTN_WHEEL_LEFT) | 2594 | if (data[1] & M560_MOUSE_BTN_WHEEL_LEFT) { |
2391 | input_report_rel(mydata->input, REL_HWHEEL, -1); | 2595 | input_report_rel(mydata->input, REL_HWHEEL, -1); |
2392 | else if (data[1] & M560_MOUSE_BTN_WHEEL_RIGHT) | 2596 | input_report_rel(mydata->input, REL_HWHEEL_HI_RES, |
2597 | -120); | ||
2598 | } else if (data[1] & M560_MOUSE_BTN_WHEEL_RIGHT) { | ||
2393 | input_report_rel(mydata->input, REL_HWHEEL, 1); | 2599 | input_report_rel(mydata->input, REL_HWHEEL, 1); |
2600 | input_report_rel(mydata->input, REL_HWHEEL_HI_RES, | ||
2601 | 120); | ||
2602 | } | ||
2394 | 2603 | ||
2395 | v = hid_snto32(hid_field_extract(hdev, data+3, 0, 12), 12); | 2604 | v = hid_snto32(hid_field_extract(hdev, data+3, 0, 12), 12); |
2396 | input_report_rel(mydata->input, REL_X, v); | 2605 | input_report_rel(mydata->input, REL_X, v); |
@@ -2399,7 +2608,8 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size) | |||
2399 | input_report_rel(mydata->input, REL_Y, v); | 2608 | input_report_rel(mydata->input, REL_Y, v); |
2400 | 2609 | ||
2401 | v = hid_snto32(data[6], 8); | 2610 | v = hid_snto32(data[6], 8); |
2402 | input_report_rel(mydata->input, REL_WHEEL, v); | 2611 | hidpp_scroll_counter_handle_scroll( |
2612 | &hidpp->vertical_wheel_counter, v); | ||
2403 | 2613 | ||
2404 | input_sync(mydata->input); | 2614 | input_sync(mydata->input); |
2405 | } | 2615 | } |
@@ -2426,6 +2636,8 @@ static void m560_populate_input(struct hidpp_device *hidpp, | |||
2426 | __set_bit(REL_Y, mydata->input->relbit); | 2636 | __set_bit(REL_Y, mydata->input->relbit); |
2427 | __set_bit(REL_WHEEL, mydata->input->relbit); | 2637 | __set_bit(REL_WHEEL, mydata->input->relbit); |
2428 | __set_bit(REL_HWHEEL, mydata->input->relbit); | 2638 | __set_bit(REL_HWHEEL, mydata->input->relbit); |
2639 | __set_bit(REL_WHEEL_HI_RES, mydata->input->relbit); | ||
2640 | __set_bit(REL_HWHEEL_HI_RES, mydata->input->relbit); | ||
2429 | } | 2641 | } |
2430 | 2642 | ||
2431 | static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi, | 2643 | static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi, |
@@ -2528,6 +2740,37 @@ static int g920_get_config(struct hidpp_device *hidpp) | |||
2528 | } | 2740 | } |
2529 | 2741 | ||
2530 | /* -------------------------------------------------------------------------- */ | 2742 | /* -------------------------------------------------------------------------- */ |
2743 | /* High-resolution scroll wheels */ | ||
2744 | /* -------------------------------------------------------------------------- */ | ||
2745 | |||
2746 | static int hi_res_scroll_enable(struct hidpp_device *hidpp) | ||
2747 | { | ||
2748 | int ret; | ||
2749 | u8 multiplier = 1; | ||
2750 | |||
2751 | if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) { | ||
2752 | ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false); | ||
2753 | if (ret == 0) | ||
2754 | ret = hidpp_hrw_get_wheel_capability(hidpp, &multiplier); | ||
2755 | } else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) { | ||
2756 | ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true, | ||
2757 | &multiplier); | ||
2758 | } else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ { | ||
2759 | ret = hidpp10_enable_scrolling_acceleration(hidpp); | ||
2760 | multiplier = 8; | ||
2761 | } | ||
2762 | if (ret) | ||
2763 | return ret; | ||
2764 | |||
2765 | if (multiplier == 0) | ||
2766 | multiplier = 1; | ||
2767 | |||
2768 | hidpp->vertical_wheel_counter.wheel_multiplier = multiplier; | ||
2769 | hid_info(hidpp->hid_dev, "multiplier = %d\n", multiplier); | ||
2770 | return 0; | ||
2771 | } | ||
2772 | |||
2773 | /* -------------------------------------------------------------------------- */ | ||
2531 | /* Generic HID++ devices */ | 2774 | /* Generic HID++ devices */ |
2532 | /* -------------------------------------------------------------------------- */ | 2775 | /* -------------------------------------------------------------------------- */ |
2533 | 2776 | ||
@@ -2572,6 +2815,9 @@ static void hidpp_populate_input(struct hidpp_device *hidpp, | |||
2572 | wtp_populate_input(hidpp, input, origin_is_hid_core); | 2815 | wtp_populate_input(hidpp, input, origin_is_hid_core); |
2573 | else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) | 2816 | else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) |
2574 | m560_populate_input(hidpp, input, origin_is_hid_core); | 2817 | m560_populate_input(hidpp, input, origin_is_hid_core); |
2818 | |||
2819 | if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) | ||
2820 | hidpp->vertical_wheel_counter.dev = input; | ||
2575 | } | 2821 | } |
2576 | 2822 | ||
2577 | static int hidpp_input_configured(struct hid_device *hdev, | 2823 | static int hidpp_input_configured(struct hid_device *hdev, |
@@ -2690,6 +2936,27 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, | |||
2690 | return 0; | 2936 | return 0; |
2691 | } | 2937 | } |
2692 | 2938 | ||
2939 | static int hidpp_event(struct hid_device *hdev, struct hid_field *field, | ||
2940 | struct hid_usage *usage, __s32 value) | ||
2941 | { | ||
2942 | /* This function will only be called for scroll events, due to the | ||
2943 | * restriction imposed in hidpp_usages. | ||
2944 | */ | ||
2945 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
2946 | struct hidpp_scroll_counter *counter = &hidpp->vertical_wheel_counter; | ||
2947 | /* A scroll event may occur before the multiplier has been retrieved or | ||
2948 | * the input device set, or high-res scroll enabling may fail. In such | ||
2949 | * cases we must return early (falling back to default behaviour) to | ||
2950 | * avoid a crash in hidpp_scroll_counter_handle_scroll. | ||
2951 | */ | ||
2952 | if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0 | ||
2953 | || counter->dev == NULL || counter->wheel_multiplier == 0) | ||
2954 | return 0; | ||
2955 | |||
2956 | hidpp_scroll_counter_handle_scroll(counter, value); | ||
2957 | return 1; | ||
2958 | } | ||
2959 | |||
2693 | static int hidpp_initialize_battery(struct hidpp_device *hidpp) | 2960 | static int hidpp_initialize_battery(struct hidpp_device *hidpp) |
2694 | { | 2961 | { |
2695 | static atomic_t battery_no = ATOMIC_INIT(0); | 2962 | static atomic_t battery_no = ATOMIC_INIT(0); |
@@ -2901,6 +3168,9 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) | |||
2901 | if (hidpp->battery.ps) | 3168 | if (hidpp->battery.ps) |
2902 | power_supply_changed(hidpp->battery.ps); | 3169 | power_supply_changed(hidpp->battery.ps); |
2903 | 3170 | ||
3171 | if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) | ||
3172 | hi_res_scroll_enable(hidpp); | ||
3173 | |||
2904 | if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input) | 3174 | if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input) |
2905 | /* if the input nodes are already created, we can stop now */ | 3175 | /* if the input nodes are already created, we can stop now */ |
2906 | return; | 3176 | return; |
@@ -3086,35 +3356,63 @@ static void hidpp_remove(struct hid_device *hdev) | |||
3086 | mutex_destroy(&hidpp->send_mutex); | 3356 | mutex_destroy(&hidpp->send_mutex); |
3087 | } | 3357 | } |
3088 | 3358 | ||
3359 | #define LDJ_DEVICE(product) \ | ||
3360 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \ | ||
3361 | USB_VENDOR_ID_LOGITECH, (product)) | ||
3362 | |||
3089 | static const struct hid_device_id hidpp_devices[] = { | 3363 | static const struct hid_device_id hidpp_devices[] = { |
3090 | { /* wireless touchpad */ | 3364 | { /* wireless touchpad */ |
3091 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3365 | LDJ_DEVICE(0x4011), |
3092 | USB_VENDOR_ID_LOGITECH, 0x4011), | ||
3093 | .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT | | 3366 | .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT | |
3094 | HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS }, | 3367 | HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS }, |
3095 | { /* wireless touchpad T650 */ | 3368 | { /* wireless touchpad T650 */ |
3096 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3369 | LDJ_DEVICE(0x4101), |
3097 | USB_VENDOR_ID_LOGITECH, 0x4101), | ||
3098 | .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT }, | 3370 | .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT }, |
3099 | { /* wireless touchpad T651 */ | 3371 | { /* wireless touchpad T651 */ |
3100 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, | 3372 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, |
3101 | USB_DEVICE_ID_LOGITECH_T651), | 3373 | USB_DEVICE_ID_LOGITECH_T651), |
3102 | .driver_data = HIDPP_QUIRK_CLASS_WTP }, | 3374 | .driver_data = HIDPP_QUIRK_CLASS_WTP }, |
3375 | { /* Mouse Logitech Anywhere MX */ | ||
3376 | LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, | ||
3377 | { /* Mouse Logitech Cube */ | ||
3378 | LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, | ||
3379 | { /* Mouse Logitech M335 */ | ||
3380 | LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3381 | { /* Mouse Logitech M515 */ | ||
3382 | LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, | ||
3103 | { /* Mouse logitech M560 */ | 3383 | { /* Mouse logitech M560 */ |
3104 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3384 | LDJ_DEVICE(0x402d), |
3105 | USB_VENDOR_ID_LOGITECH, 0x402d), | 3385 | .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 |
3106 | .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 }, | 3386 | | HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, |
3387 | { /* Mouse Logitech M705 (firmware RQM17) */ | ||
3388 | LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, | ||
3389 | { /* Mouse Logitech M705 (firmware RQM67) */ | ||
3390 | LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3391 | { /* Mouse Logitech M720 */ | ||
3392 | LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3393 | { /* Mouse Logitech MX Anywhere 2 */ | ||
3394 | LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3395 | { LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3396 | { LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3397 | { LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3398 | { /* Mouse Logitech MX Anywhere 2S */ | ||
3399 | LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3400 | { /* Mouse Logitech MX Master */ | ||
3401 | LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3402 | { LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3403 | { LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3404 | { /* Mouse Logitech MX Master 2S */ | ||
3405 | LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | ||
3406 | { /* Mouse Logitech Performance MX */ | ||
3407 | LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, | ||
3107 | { /* Keyboard logitech K400 */ | 3408 | { /* Keyboard logitech K400 */ |
3108 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3409 | LDJ_DEVICE(0x4024), |
3109 | USB_VENDOR_ID_LOGITECH, 0x4024), | ||
3110 | .driver_data = HIDPP_QUIRK_CLASS_K400 }, | 3410 | .driver_data = HIDPP_QUIRK_CLASS_K400 }, |
3111 | { /* Solar Keyboard Logitech K750 */ | 3411 | { /* Solar Keyboard Logitech K750 */ |
3112 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3412 | LDJ_DEVICE(0x4002), |
3113 | USB_VENDOR_ID_LOGITECH, 0x4002), | ||
3114 | .driver_data = HIDPP_QUIRK_CLASS_K750 }, | 3413 | .driver_data = HIDPP_QUIRK_CLASS_K750 }, |
3115 | 3414 | ||
3116 | { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | 3415 | { LDJ_DEVICE(HID_ANY_ID) }, |
3117 | USB_VENDOR_ID_LOGITECH, HID_ANY_ID)}, | ||
3118 | 3416 | ||
3119 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL), | 3417 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL), |
3120 | .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS}, | 3418 | .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS}, |
@@ -3123,12 +3421,19 @@ static const struct hid_device_id hidpp_devices[] = { | |||
3123 | 3421 | ||
3124 | MODULE_DEVICE_TABLE(hid, hidpp_devices); | 3422 | MODULE_DEVICE_TABLE(hid, hidpp_devices); |
3125 | 3423 | ||
3424 | static const struct hid_usage_id hidpp_usages[] = { | ||
3425 | { HID_GD_WHEEL, EV_REL, REL_WHEEL_HI_RES }, | ||
3426 | { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} | ||
3427 | }; | ||
3428 | |||
3126 | static struct hid_driver hidpp_driver = { | 3429 | static struct hid_driver hidpp_driver = { |
3127 | .name = "logitech-hidpp-device", | 3430 | .name = "logitech-hidpp-device", |
3128 | .id_table = hidpp_devices, | 3431 | .id_table = hidpp_devices, |
3129 | .probe = hidpp_probe, | 3432 | .probe = hidpp_probe, |
3130 | .remove = hidpp_remove, | 3433 | .remove = hidpp_remove, |
3131 | .raw_event = hidpp_raw_event, | 3434 | .raw_event = hidpp_raw_event, |
3435 | .usage_table = hidpp_usages, | ||
3436 | .event = hidpp_event, | ||
3132 | .input_configured = hidpp_input_configured, | 3437 | .input_configured = hidpp_input_configured, |
3133 | .input_mapping = hidpp_input_mapping, | 3438 | .input_mapping = hidpp_input_mapping, |
3134 | .input_mapped = hidpp_input_mapped, | 3439 | .input_mapped = hidpp_input_mapped, |
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 4a44e48e08b2..9fc51eff1079 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c | |||
@@ -107,8 +107,6 @@ out: | |||
107 | 107 | ||
108 | /* | 108 | /* |
109 | * The first byte of the report buffer is expected to be a report number. | 109 | * The first byte of the report buffer is expected to be a report number. |
110 | * | ||
111 | * This function is to be called with the minors_lock mutex held. | ||
112 | */ | 110 | */ |
113 | static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type) | 111 | static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type) |
114 | { | 112 | { |
@@ -117,6 +115,8 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, | |||
117 | __u8 *buf; | 115 | __u8 *buf; |
118 | int ret = 0; | 116 | int ret = 0; |
119 | 117 | ||
118 | lockdep_assert_held(&minors_lock); | ||
119 | |||
120 | if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { | 120 | if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { |
121 | ret = -ENODEV; | 121 | ret = -ENODEV; |
122 | goto out; | 122 | goto out; |
@@ -181,8 +181,6 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t | |||
181 | * of buffer is the report number to request, or 0x0 if the defice does not | 181 | * of buffer is the report number to request, or 0x0 if the defice does not |
182 | * use numbered reports. The report_type parameter can be HID_FEATURE_REPORT | 182 | * use numbered reports. The report_type parameter can be HID_FEATURE_REPORT |
183 | * or HID_INPUT_REPORT. | 183 | * or HID_INPUT_REPORT. |
184 | * | ||
185 | * This function is to be called with the minors_lock mutex held. | ||
186 | */ | 184 | */ |
187 | static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type) | 185 | static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type) |
188 | { | 186 | { |
@@ -192,6 +190,8 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t | |||
192 | int ret = 0, len; | 190 | int ret = 0, len; |
193 | unsigned char report_number; | 191 | unsigned char report_number; |
194 | 192 | ||
193 | lockdep_assert_held(&minors_lock); | ||
194 | |||
195 | if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { | 195 | if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { |
196 | ret = -ENODEV; | 196 | ret = -ENODEV; |
197 | goto out; | 197 | goto out; |
diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c index 89f2976f9c53..fd1b6eea6d2f 100644 --- a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c +++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | |||
@@ -346,6 +346,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = { | |||
346 | }, | 346 | }, |
347 | .driver_data = (void *)&sipodev_desc | 347 | .driver_data = (void *)&sipodev_desc |
348 | }, | 348 | }, |
349 | { | ||
350 | .ident = "Odys Winbook 13", | ||
351 | .matches = { | ||
352 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "AXDIA International GmbH"), | ||
353 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "WINBOOK 13"), | ||
354 | }, | ||
355 | .driver_data = (void *)&sipodev_desc | ||
356 | }, | ||
349 | { } /* Terminate list */ | 357 | { } /* Terminate list */ |
350 | }; | 358 | }; |
351 | 359 | ||
diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 8793cc49f855..a6e1ee744f4d 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c | |||
@@ -117,6 +117,7 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
117 | { | 117 | { |
118 | int ret; | 118 | int ret; |
119 | struct ish_hw *hw; | 119 | struct ish_hw *hw; |
120 | unsigned long irq_flag = 0; | ||
120 | struct ishtp_device *ishtp; | 121 | struct ishtp_device *ishtp; |
121 | struct device *dev = &pdev->dev; | 122 | struct device *dev = &pdev->dev; |
122 | 123 | ||
@@ -156,8 +157,12 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
156 | pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3; | 157 | pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3; |
157 | 158 | ||
158 | /* request and enable interrupt */ | 159 | /* request and enable interrupt */ |
160 | ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); | ||
161 | if (!pdev->msi_enabled && !pdev->msix_enabled) | ||
162 | irq_flag = IRQF_SHARED; | ||
163 | |||
159 | ret = devm_request_irq(dev, pdev->irq, ish_irq_handler, | 164 | ret = devm_request_irq(dev, pdev->irq, ish_irq_handler, |
160 | IRQF_SHARED, KBUILD_MODNAME, ishtp); | 165 | irq_flag, KBUILD_MODNAME, ishtp); |
161 | if (ret) { | 166 | if (ret) { |
162 | dev_err(dev, "ISH: request IRQ %d failed\n", pdev->irq); | 167 | dev_err(dev, "ISH: request IRQ %d failed\n", pdev->irq); |
163 | return ret; | 168 | return ret; |
diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.c b/drivers/hid/intel-ish-hid/ishtp-hid.c index cd23903ddcf1..e918d78e541c 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid.c | |||
@@ -222,7 +222,7 @@ int ishtp_hid_probe(unsigned int cur_hid_dev, | |||
222 | err_hid_device: | 222 | err_hid_device: |
223 | kfree(hid_data); | 223 | kfree(hid_data); |
224 | err_hid_data: | 224 | err_hid_data: |
225 | kfree(hid); | 225 | hid_destroy_device(hid); |
226 | return rv; | 226 | return rv; |
227 | } | 227 | } |
228 | 228 | ||
diff --git a/include/linux/hid.h b/include/linux/hid.h index a355d61940f2..d99287327ef2 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -219,6 +219,7 @@ struct hid_item { | |||
219 | #define HID_GD_VBRZ 0x00010045 | 219 | #define HID_GD_VBRZ 0x00010045 |
220 | #define HID_GD_VNO 0x00010046 | 220 | #define HID_GD_VNO 0x00010046 |
221 | #define HID_GD_FEATURE 0x00010047 | 221 | #define HID_GD_FEATURE 0x00010047 |
222 | #define HID_GD_RESOLUTION_MULTIPLIER 0x00010048 | ||
222 | #define HID_GD_SYSTEM_CONTROL 0x00010080 | 223 | #define HID_GD_SYSTEM_CONTROL 0x00010080 |
223 | #define HID_GD_UP 0x00010090 | 224 | #define HID_GD_UP 0x00010090 |
224 | #define HID_GD_DOWN 0x00010091 | 225 | #define HID_GD_DOWN 0x00010091 |
@@ -232,12 +233,14 @@ struct hid_item { | |||
232 | #define HID_DC_BATTERYSTRENGTH 0x00060020 | 233 | #define HID_DC_BATTERYSTRENGTH 0x00060020 |
233 | 234 | ||
234 | #define HID_CP_CONSUMER_CONTROL 0x000c0001 | 235 | #define HID_CP_CONSUMER_CONTROL 0x000c0001 |
236 | #define HID_CP_AC_PAN 0x000c0238 | ||
235 | 237 | ||
236 | #define HID_DG_DIGITIZER 0x000d0001 | 238 | #define HID_DG_DIGITIZER 0x000d0001 |
237 | #define HID_DG_PEN 0x000d0002 | 239 | #define HID_DG_PEN 0x000d0002 |
238 | #define HID_DG_LIGHTPEN 0x000d0003 | 240 | #define HID_DG_LIGHTPEN 0x000d0003 |
239 | #define HID_DG_TOUCHSCREEN 0x000d0004 | 241 | #define HID_DG_TOUCHSCREEN 0x000d0004 |
240 | #define HID_DG_TOUCHPAD 0x000d0005 | 242 | #define HID_DG_TOUCHPAD 0x000d0005 |
243 | #define HID_DG_WHITEBOARD 0x000d0006 | ||
241 | #define HID_DG_STYLUS 0x000d0020 | 244 | #define HID_DG_STYLUS 0x000d0020 |
242 | #define HID_DG_PUCK 0x000d0021 | 245 | #define HID_DG_PUCK 0x000d0021 |
243 | #define HID_DG_FINGER 0x000d0022 | 246 | #define HID_DG_FINGER 0x000d0022 |
@@ -427,6 +430,7 @@ struct hid_local { | |||
427 | */ | 430 | */ |
428 | 431 | ||
429 | struct hid_collection { | 432 | struct hid_collection { |
433 | struct hid_collection *parent; | ||
430 | unsigned type; | 434 | unsigned type; |
431 | unsigned usage; | 435 | unsigned usage; |
432 | unsigned level; | 436 | unsigned level; |
@@ -436,12 +440,16 @@ struct hid_usage { | |||
436 | unsigned hid; /* hid usage code */ | 440 | unsigned hid; /* hid usage code */ |
437 | unsigned collection_index; /* index into collection array */ | 441 | unsigned collection_index; /* index into collection array */ |
438 | unsigned usage_index; /* index into usage array */ | 442 | unsigned usage_index; /* index into usage array */ |
443 | __s8 resolution_multiplier;/* Effective Resolution Multiplier | ||
444 | (HUT v1.12, 4.3.1), default: 1 */ | ||
439 | /* hidinput data */ | 445 | /* hidinput data */ |
446 | __s8 wheel_factor; /* 120/resolution_multiplier */ | ||
440 | __u16 code; /* input driver code */ | 447 | __u16 code; /* input driver code */ |
441 | __u8 type; /* input driver type */ | 448 | __u8 type; /* input driver type */ |
442 | __s8 hat_min; /* hat switch fun */ | 449 | __s8 hat_min; /* hat switch fun */ |
443 | __s8 hat_max; /* ditto */ | 450 | __s8 hat_max; /* ditto */ |
444 | __s8 hat_dir; /* ditto */ | 451 | __s8 hat_dir; /* ditto */ |
452 | __s16 wheel_accumulated; /* hi-res wheel */ | ||
445 | }; | 453 | }; |
446 | 454 | ||
447 | struct hid_input; | 455 | struct hid_input; |
@@ -650,6 +658,7 @@ struct hid_parser { | |||
650 | unsigned int *collection_stack; | 658 | unsigned int *collection_stack; |
651 | unsigned int collection_stack_ptr; | 659 | unsigned int collection_stack_ptr; |
652 | unsigned int collection_stack_size; | 660 | unsigned int collection_stack_size; |
661 | struct hid_collection *active_collection; | ||
653 | struct hid_device *device; | 662 | struct hid_device *device; |
654 | unsigned int scan_flags; | 663 | unsigned int scan_flags; |
655 | }; | 664 | }; |
@@ -836,7 +845,11 @@ static inline bool hid_is_using_ll_driver(struct hid_device *hdev, | |||
836 | 845 | ||
837 | /* Applications from HID Usage Tables 4/8/99 Version 1.1 */ | 846 | /* Applications from HID Usage Tables 4/8/99 Version 1.1 */ |
838 | /* We ignore a few input applications that are not widely used */ | 847 | /* We ignore a few input applications that are not widely used */ |
839 | #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || ((a >= 0x000d0002) && (a <= 0x000d0006))) | 848 | #define IS_INPUT_APPLICATION(a) \ |
849 | (((a >= HID_UP_GENDESK) && (a <= HID_GD_MULTIAXIS)) \ | ||
850 | || ((a >= HID_DG_PEN) && (a <= HID_DG_WHITEBOARD)) \ | ||
851 | || (a == HID_GD_SYSTEM_CONTROL) || (a == HID_CP_CONSUMER_CONTROL) \ | ||
852 | || (a == HID_GD_WIRELESS_RADIO_CTLS)) | ||
840 | 853 | ||
841 | /* HID core API */ | 854 | /* HID core API */ |
842 | 855 | ||
@@ -892,6 +905,8 @@ struct hid_report *hid_validate_values(struct hid_device *hid, | |||
892 | unsigned int type, unsigned int id, | 905 | unsigned int type, unsigned int id, |
893 | unsigned int field_index, | 906 | unsigned int field_index, |
894 | unsigned int report_counts); | 907 | unsigned int report_counts); |
908 | |||
909 | void hid_setup_resolution_multiplier(struct hid_device *hid); | ||
895 | int hid_open_report(struct hid_device *device); | 910 | int hid_open_report(struct hid_device *device); |
896 | int hid_check_keys_pressed(struct hid_device *hid); | 911 | int hid_check_keys_pressed(struct hid_device *hid); |
897 | int hid_connect(struct hid_device *hid, unsigned int connect_mask); | 912 | int hid_connect(struct hid_device *hid, unsigned int connect_mask); |
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index ae366b87426a..7f14d4a66c28 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h | |||
@@ -716,6 +716,8 @@ | |||
716 | * the situation described above. | 716 | * the situation described above. |
717 | */ | 717 | */ |
718 | #define REL_RESERVED 0x0a | 718 | #define REL_RESERVED 0x0a |
719 | #define REL_WHEEL_HI_RES 0x0b | ||
720 | #define REL_HWHEEL_HI_RES 0x0c | ||
719 | #define REL_MAX 0x0f | 721 | #define REL_MAX 0x0f |
720 | #define REL_CNT (REL_MAX+1) | 722 | #define REL_CNT (REL_MAX+1) |
721 | 723 | ||
diff --git a/samples/hidraw/hid-example.c b/samples/hidraw/hid-example.c index 9bfd8ff6de82..37a0ffcb4d63 100644 --- a/samples/hidraw/hid-example.c +++ b/samples/hidraw/hid-example.c | |||
@@ -119,7 +119,7 @@ int main(int argc, char **argv) | |||
119 | if (res < 0) | 119 | if (res < 0) |
120 | perror("HIDIOCSFEATURE"); | 120 | perror("HIDIOCSFEATURE"); |
121 | else | 121 | else |
122 | printf("ioctl HIDIOCGFEATURE returned: %d\n", res); | 122 | printf("ioctl HIDIOCSFEATURE returned: %d\n", res); |
123 | 123 | ||
124 | /* Get Feature */ | 124 | /* Get Feature */ |
125 | buf[0] = 0x9; /* Report Number */ | 125 | buf[0] = 0x9; /* Report Number */ |