HID: nintendo: reduce device removal subcommand errors
authorDaniel J. Ogorchock <djogorchock@gmail.com>
Sat, 11 Sep 2021 17:36:31 +0000 (13:36 -0400)
committerJiri Kosina <jkosina@suse.cz>
Wed, 27 Oct 2021 08:05:51 +0000 (10:05 +0200)
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>
drivers/hid/hid-nintendo.c

index b5e9d89..ed9cf7b 100644 (file)
@@ -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);
 }