| From: Tomasz Kramkowski <tk@the-tk.com> |
| Date: Tue, 14 Mar 2017 13:29:13 +0000 |
| Subject: HID: clamp input to logical range if no null state |
| |
| commit c3883fe06488a483658ba5d849b70e49bee15e7c upstream. |
| |
| This patch fixes an issue in drivers/hid/hid-input.c where values |
| outside of the logical range are not clamped when "null state" bit of |
| the input control is not set. |
| |
| This was discussed on the lists [1] and this change stems from the fact |
| due to the ambiguity of the HID specification it might be appropriate to |
| follow Microsoft's own interpretation of the specification. As noted in |
| Microsoft's documentation [2] in the section titled "Required HID usages |
| for digitizers" it is noted that values reported outside the logical |
| range "will be considered as invalid data and the value will be changed |
| to the nearest boundary value (logical min/max)." |
| |
| This patch fixes an issue where the (1292:4745) Innomedia INNEX |
| GENESIS/ATARI reports out of range values for its X and Y axis of the |
| DPad which, due to the null state bit being unset, are forwarded to |
| userspace as is. Now these values will get clamped to the logical range |
| before being forwarded to userspace. This device was also used to test |
| this patch. |
| |
| This patch expands on commit 3f3752705dbd ("HID: reject input outside |
| logical range only if null state is set"). |
| |
| [1]: http://lkml.kernel.org/r/20170307131036.GA853@gaia.local |
| [2]: https://msdn.microsoft.com/en-us/library/windows/hardware/dn672278(v=vs.85).asp |
| |
| Signed-off-by: Tomasz Kramkowski <tk@the-tk.com> |
| Acked-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> |
| Signed-off-by: Jiri Kosina <jkosina@suse.cz> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| drivers/hid/hid-input.c | 21 ++++++++++++++------- |
| 1 file changed, 14 insertions(+), 7 deletions(-) |
| |
| --- a/drivers/hid/hid-input.c |
| +++ b/drivers/hid/hid-input.c |
| @@ -1087,19 +1087,26 @@ void hidinput_hid_event(struct hid_devic |
| |
| /* |
| * Ignore out-of-range values as per HID specification, |
| - * section 5.10 and 6.2.25. |
| + * section 5.10 and 6.2.25, when NULL state bit is present. |
| + * When it's not, clamp the value to match Microsoft's input |
| + * driver as mentioned in "Required HID usages for digitizers": |
| + * https://msdn.microsoft.com/en-us/library/windows/hardware/dn672278(v=vs.85).asp |
| * |
| * The logical_minimum < logical_maximum check is done so that we |
| * don't unintentionally discard values sent by devices which |
| * don't specify logical min and max. |
| */ |
| if ((field->flags & HID_MAIN_ITEM_VARIABLE) && |
| - (field->flags & HID_MAIN_ITEM_NULL_STATE) && |
| - (field->logical_minimum < field->logical_maximum) && |
| - (value < field->logical_minimum || |
| - value > field->logical_maximum)) { |
| - dbg_hid("Ignoring out-of-range value %x\n", value); |
| - return; |
| + (field->logical_minimum < field->logical_maximum)) { |
| + if (field->flags & HID_MAIN_ITEM_NULL_STATE && |
| + (value < field->logical_minimum || |
| + value > field->logical_maximum)) { |
| + dbg_hid("Ignoring out-of-range value %x\n", value); |
| + return; |
| + } |
| + value = clamp(value, |
| + field->logical_minimum, |
| + field->logical_maximum); |
| } |
| |
| /* |