Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: logitech-dj: Fix probe failure when used with KVM

Since commit 6f20d3261265 ("HID: logitech-dj: Fix error handling in
logi_dj_recv_switch_to_dj_mode()") logi_dj_recv_switch_to_dj_mode()
will return an error when the hid_hw_raw_request() call to enable
[dis]connect events fails.

This can happen when used with a KVM like the Aten CS1784a and the PC
does not have the KVM focus when probe() runs, which causes probe() to
fail after which the receiver will simply not work.

The logi_dj_recv_query_paired_devices() call done at the end of probe()
already ignores any errors for the KVM without focus case. When focus is
restored and an input report is received this will trigger
logi_dj_recv_queue_unknown_work() which retries the query_paired_devices()
call from a workqueue.

To fix the probe() failure let it ignore logi_dj_recv_switch_to_dj_mode()
errors too, track if a successful logi_dj_recv_switch_to_dj_mode() was
done and retry if necessary from logi_dj_recv_queue_unknown_work().

Queurying paired devices while not in dj-mode is not useful and this
will be redone after the unknown work has retried setting dj-mode,
so skip queurying paired devices when not in dj-mode yet.

The new bool to track successful setting of the dj-mode will also cause
setting dj-mode to be retried from the unknown work, if setting dj-mode
failed after a reset_resume.

Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>

authored by

Hans de Goede and committed by
Jiri Kosina
36dcfa46 ca389a55

+16 -8
+16 -8
drivers/hid/hid-logitech-dj.c
··· 148 148 struct kfifo notif_fifo; 149 149 unsigned long last_query; /* in jiffies */ 150 150 bool ready; 151 + bool dj_mode; 151 152 enum recvr_type type; 152 153 unsigned int unnumbered_application; 153 154 spinlock_t lock; ··· 558 557 static const struct hid_ll_driver logi_dj_ll_driver; 559 558 560 559 static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev); 560 + static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev, 561 + unsigned int timeout); 561 562 static void delayedwork_callback(struct work_struct *work); 562 563 563 564 static LIST_HEAD(dj_hdev_list); ··· 844 841 logi_dj_recv_destroy_djhid_device(djrcv_dev, &workitem); 845 842 break; 846 843 case WORKITEM_TYPE_UNKNOWN: 844 + if (!djrcv_dev->dj_mode) 845 + logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); 846 + 847 847 logi_dj_recv_query_paired_devices(djrcv_dev); 848 848 break; 849 849 case WORKITEM_TYPE_EMPTY: ··· 1240 1234 1241 1235 djrcv_dev->last_query = jiffies; 1242 1236 1237 + if (!djrcv_dev->dj_mode) 1238 + return 0; 1239 + 1243 1240 if (djrcv_dev->type != recvr_type_dj) { 1244 1241 retval = logi_dj_recv_query_hidpp_devices(djrcv_dev); 1245 1242 goto out; ··· 1326 1317 if (retval < 0) 1327 1318 hid_err(hdev, "%s error:%d\n", __func__, retval); 1328 1319 1320 + djrcv_dev->dj_mode = retval >= 0; 1329 1321 return retval; 1330 1322 } 1331 1323 ··· 1847 1837 } 1848 1838 1849 1839 if (has_hidpp) { 1850 - retval = logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); 1851 - if (retval < 0) 1852 - goto switch_to_dj_mode_fail; 1840 + /* 1841 + * This can fail with a KVM. Ignore errors to let the probe 1842 + * succeed, logi_dj_recv_queue_unknown_work will retry later. 1843 + */ 1844 + logi_dj_recv_switch_to_dj_mode(djrcv_dev, 0); 1853 1845 } 1854 1846 1855 1847 /* This is enabling the polling urb on the IN endpoint */ ··· 1869 1857 spin_lock_irqsave(&djrcv_dev->lock, flags); 1870 1858 djrcv_dev->ready = true; 1871 1859 spin_unlock_irqrestore(&djrcv_dev->lock, flags); 1872 - /* 1873 - * This can fail with a KVM. Ignore errors to let the probe 1874 - * succeed, logi_dj_recv_queue_unknown_work will retry later. 1875 - */ 1860 + /* This too can fail with a KVM, ignore errors. */ 1876 1861 logi_dj_recv_query_paired_devices(djrcv_dev); 1877 1862 } 1878 1863 1879 1864 return 0; 1880 1865 1881 1866 llopen_failed: 1882 - switch_to_dj_mode_fail: 1883 1867 hid_hw_stop(hdev); 1884 1868 1885 1869 hid_hw_start_fail: