Merge branch 'for-6.5/core' into for-linus
authorJiri Kosina <jkosina@suse.cz>
Tue, 27 Jun 2023 20:38:37 +0000 (22:38 +0200)
committerJiri Kosina <jkosina@suse.cz>
Tue, 27 Jun 2023 20:38:37 +0000 (22:38 +0200)
- more bullet-proof handling of devres-managed resources in HID core
  (Dmitry Torokhov)
- kunit test Kconfig dependency fix (Geert Uytterhoeven)

drivers/hid/Kconfig
drivers/hid/hid-core.c
include/linux/hid.h

index 4ce012f..b977450 100644 (file)
@@ -1285,7 +1285,7 @@ config HID_MCP2221
 
 config HID_KUNIT_TEST
        tristate "KUnit tests for HID" if !KUNIT_ALL_TESTS
-       depends on KUNIT=y
+       depends on KUNIT
        depends on HID_BATTERY_STRENGTH
        depends on HID_UCLOGIC
        default KUNIT_ALL_TESTS
index 22623eb..8992e3c 100644 (file)
@@ -2587,64 +2587,84 @@ bool hid_compare_device_paths(struct hid_device *hdev_a,
 }
 EXPORT_SYMBOL_GPL(hid_compare_device_paths);
 
+static bool hid_check_device_match(struct hid_device *hdev,
+                                  struct hid_driver *hdrv,
+                                  const struct hid_device_id **id)
+{
+       *id = hid_match_device(hdev, hdrv);
+       if (!*id)
+               return false;
+
+       if (hdrv->match)
+               return hdrv->match(hdev, hid_ignore_special_drivers);
+
+       /*
+        * hid-generic implements .match(), so we must be dealing with a
+        * different HID driver here, and can simply check if
+        * hid_ignore_special_drivers is set or not.
+        */
+       return !hid_ignore_special_drivers;
+}
+
+static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)
+{
+       const struct hid_device_id *id;
+       int ret;
+
+       if (!hid_check_device_match(hdev, hdrv, &id))
+               return -ENODEV;
+
+       hdev->devres_group_id = devres_open_group(&hdev->dev, NULL, GFP_KERNEL);
+       if (!hdev->devres_group_id)
+               return -ENOMEM;
+
+       /* reset the quirks that has been previously set */
+       hdev->quirks = hid_lookup_quirk(hdev);
+       hdev->driver = hdrv;
+
+       if (hdrv->probe) {
+               ret = hdrv->probe(hdev, id);
+       } else { /* default probe */
+               ret = hid_open_report(hdev);
+               if (!ret)
+                       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       }
+
+       /*
+        * Note that we are not closing the devres group opened above so
+        * even resources that were attached to the device after probe is
+        * run are released when hid_device_remove() is executed. This is
+        * needed as some drivers would allocate additional resources,
+        * for example when updating firmware.
+        */
+
+       if (ret) {
+               devres_release_group(&hdev->dev, hdev->devres_group_id);
+               hid_close_report(hdev);
+               hdev->driver = NULL;
+       }
+
+       return ret;
+}
+
 static int hid_device_probe(struct device *dev)
 {
-       struct hid_driver *hdrv = to_hid_driver(dev->driver);
        struct hid_device *hdev = to_hid_device(dev);
-       const struct hid_device_id *id;
+       struct hid_driver *hdrv = to_hid_driver(dev->driver);
        int ret = 0;
 
-       if (down_interruptible(&hdev->driver_input_lock)) {
-               ret = -EINTR;
-               goto end;
-       }
-       hdev->io_started = false;
+       if (down_interruptible(&hdev->driver_input_lock))
+               return -EINTR;
 
+       hdev->io_started = false;
        clear_bit(ffs(HID_STAT_REPROBED), &hdev->status);
 
-       if (!hdev->driver) {
-               id = hid_match_device(hdev, hdrv);
-               if (id == NULL) {
-                       ret = -ENODEV;
-                       goto unlock;
-               }
-
-               if (hdrv->match) {
-                       if (!hdrv->match(hdev, hid_ignore_special_drivers)) {
-                               ret = -ENODEV;
-                               goto unlock;
-                       }
-               } else {
-                       /*
-                        * hid-generic implements .match(), so if
-                        * hid_ignore_special_drivers is set, we can safely
-                        * return.
-                        */
-                       if (hid_ignore_special_drivers) {
-                               ret = -ENODEV;
-                               goto unlock;
-                       }
-               }
+       if (!hdev->driver)
+               ret = __hid_device_probe(hdev, hdrv);
 
-               /* reset the quirks that has been previously set */
-               hdev->quirks = hid_lookup_quirk(hdev);
-               hdev->driver = hdrv;
-               if (hdrv->probe) {
-                       ret = hdrv->probe(hdev, id);
-               } else { /* default probe */
-                       ret = hid_open_report(hdev);
-                       if (!ret)
-                               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-               }
-               if (ret) {
-                       hid_close_report(hdev);
-                       hdev->driver = NULL;
-               }
-       }
-unlock:
        if (!hdev->io_started)
                up(&hdev->driver_input_lock);
-end:
+
        return ret;
 }
 
@@ -2662,6 +2682,10 @@ static void hid_device_remove(struct device *dev)
                        hdrv->remove(hdev);
                else /* default remove */
                        hid_hw_stop(hdev);
+
+               /* Release all devres resources allocated by the driver */
+               devres_release_group(&hdev->dev, hdev->devres_group_id);
+
                hid_close_report(hdev);
                hdev->driver = NULL;
        }
index 4e4c4fe..39e21e3 100644 (file)
@@ -597,6 +597,7 @@ struct hid_device {                                                 /* device report descriptor */
        struct semaphore driver_input_lock;                             /* protects the current driver */
        struct device dev;                                              /* device */
        struct hid_driver *driver;
+       void *devres_group_id;                                          /* ID of probe devres group     */
 
        const struct hid_ll_driver *ll_driver;
        struct mutex ll_open_lock;