diff options
author | Hans de Goede <hdegoede@redhat.com> | 2019-04-20 13:21:59 +0200 |
---|---|---|
committer | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2019-04-23 18:01:40 +0200 |
commit | da12b224b7d514215f4ed978abe03e8100d0426c (patch) | |
tree | c699d64050f184e4af4cf16beebe0db9b5f0a927 /drivers/hid | |
parent | aca22a35396c52492cd61965544c134c74daca68 (diff) | |
download | linux-da12b224b7d514215f4ed978abe03e8100d0426c.tar.bz2 |
HID: logitech-dj: deal with some KVMs adding an extra interface to the usbdev
My Aten cs1764a KVM adds an extra interface to the receiver through which
it forwards mouse events, if a separate mouse is plugged in next to the
receiver dongle. This interface is present even if no extra mouse is
plugged in.
logitech-dj trying to handle this extra interface causes mouse events send
through the extra interface to not be properly handled.
This commit fixes this by treating any extra interfaces as hid-generic
interfaces.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-logitech-dj.c | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index c73ceb31b94e..5f06b80bb404 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/kfifo.h> #include <linux/delay.h> +#include <linux/usb.h> /* For to_usb_interface for kvm extra intf check */ #include <asm/unaligned.h> #include "hid-ids.h" @@ -1463,6 +1464,9 @@ static int logi_dj_raw_event(struct hid_device *hdev, struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); dbg_hid("%s, size:%d\n", __func__, size); + if (!djrcv_dev) + return 0; + if (!hdev->report_enum[HID_INPUT_REPORT].numbered) { if (djrcv_dev->unnumbered_application == HID_GD_KEYBOARD) { @@ -1532,6 +1536,8 @@ static int logi_dj_probe(struct hid_device *hdev, struct hid_report_enum *rep_enum; struct hid_report *rep; struct dj_receiver_dev *djrcv_dev; + struct usb_interface *intf; + unsigned int no_dj_interfaces = 0; bool has_hidpp = false; unsigned long flags; int retval; @@ -1547,6 +1553,27 @@ static int logi_dj_probe(struct hid_device *hdev, return retval; } + /* + * Some KVMs add an extra interface for e.g. mouse emulation. If we + * treat these as logitech-dj interfaces then this causes input events + * reported through this extra interface to not be reported correctly. + * To avoid this, we treat these as generic-hid devices. + */ + switch (id->driver_data) { + case recvr_type_dj: no_dj_interfaces = 3; break; + case recvr_type_hidpp: no_dj_interfaces = 2; break; + case recvr_type_gaming_hidpp: no_dj_interfaces = 3; break; + case recvr_type_27mhz: no_dj_interfaces = 2; break; + } + if (hid_is_using_ll_driver(hdev, &usb_hid_driver)) { + intf = to_usb_interface(hdev->dev.parent); + if (intf && intf->altsetting->desc.bInterfaceNumber >= + no_dj_interfaces) { + hdev->quirks |= HID_QUIRK_INPUT_PER_APP; + return hid_hw_start(hdev, HID_CONNECT_DEFAULT); + } + } + rep_enum = &hdev->report_enum[HID_INPUT_REPORT]; /* no input reports, bail out */ @@ -1642,7 +1669,7 @@ static int logi_dj_reset_resume(struct hid_device *hdev) int retval; struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev); - if (djrcv_dev->hidpp != hdev) + if (!djrcv_dev || djrcv_dev->hidpp != hdev) return 0; retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); @@ -1664,6 +1691,9 @@ static void logi_dj_remove(struct hid_device *hdev) dbg_hid("%s\n", __func__); + if (!djrcv_dev) + return hid_hw_stop(hdev); + /* * This ensures that if the work gets requeued from another * interface of the same receiver it will be a no-op. |