summaryrefslogtreecommitdiff
path: root/drivers/hid/hid-nintendo.c
diff options
context:
space:
mode:
authorDaniel J. Ogorchock <djogorchock@gmail.com>2021-09-11 20:36:31 +0300
committerJiri Kosina <jkosina@suse.cz>2021-10-27 11:05:51 +0300
commit012bd52c699d6197223b2e7cdce6dc2ec1858343 (patch)
tree08d6f35eb732460e18f31a557c9f043111d0abaa /drivers/hid/hid-nintendo.c
parentc7d0d636171fe9ece7a05ed88bf6a1d2af844ddd (diff)
downloadlinux-012bd52c699d6197223b2e7cdce6dc2ec1858343.tar.xz
HID: nintendo: reduce device removal subcommand errors
This patch fixes meaningless error output from trying to send subcommands immediately after controller removal. It now disables subcommands as soon as possible on removal. Signed-off-by: Daniel J. Ogorchock <djogorchock@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-nintendo.c')
-rw-r--r--drivers/hid/hid-nintendo.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c
index b5e9d89b3fd2..ed9cf7b37306 100644
--- a/drivers/hid/hid-nintendo.c
+++ b/drivers/hid/hid-nintendo.c
@@ -230,6 +230,7 @@ static const struct joycon_rumble_amp_data joycon_rumble_amplitudes[] = {
enum joycon_ctlr_state {
JOYCON_CTLR_STATE_INIT,
JOYCON_CTLR_STATE_READ,
+ JOYCON_CTLR_STATE_REMOVED,
};
struct joycon_stick_cal {
@@ -458,6 +459,14 @@ static int joycon_send_subcmd(struct joycon_ctlr *ctlr,
unsigned long flags;
spin_lock_irqsave(&ctlr->lock, flags);
+ /*
+ * If the controller has been removed, just return ENODEV so the LED
+ * subsystem doesn't print invalid errors on removal.
+ */
+ if (ctlr->ctlr_state == JOYCON_CTLR_STATE_REMOVED) {
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+ return -ENODEV;
+ }
memcpy(subcmd->rumble_data, ctlr->rumble_data[ctlr->rumble_queue_tail],
JC_RUMBLE_DATA_SIZE);
spin_unlock_irqrestore(&ctlr->lock, flags);
@@ -807,10 +816,13 @@ static void joycon_rumble_worker(struct work_struct *work)
mutex_lock(&ctlr->output_mutex);
ret = joycon_enable_rumble(ctlr);
mutex_unlock(&ctlr->output_mutex);
- if (ret < 0)
- hid_warn(ctlr->hdev, "Failed to set rumble; e=%d", ret);
+ /* -ENODEV means the controller was just unplugged */
spin_lock_irqsave(&ctlr->lock, flags);
+ if (ret < 0 && ret != -ENODEV &&
+ ctlr->ctlr_state != JOYCON_CTLR_STATE_REMOVED)
+ hid_warn(ctlr->hdev, "Failed to set rumble; e=%d", ret);
+
ctlr->rumble_msecs = jiffies_to_msecs(jiffies);
if (ctlr->rumble_queue_tail != ctlr->rumble_queue_head) {
if (++ctlr->rumble_queue_tail >= JC_RUMBLE_QUEUE_SIZE)
@@ -1529,9 +1541,17 @@ err:
static void nintendo_hid_remove(struct hid_device *hdev)
{
struct joycon_ctlr *ctlr = hid_get_drvdata(hdev);
+ unsigned long flags;
hid_dbg(hdev, "remove\n");
+
+ /* Prevent further attempts at sending subcommands. */
+ spin_lock_irqsave(&ctlr->lock, flags);
+ ctlr->ctlr_state = JOYCON_CTLR_STATE_REMOVED;
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+
destroy_workqueue(ctlr->rumble_queue);
+
hid_hw_close(hdev);
hid_hw_stop(hdev);
}