Commit 1639f986 authored by Jiri Kosina's avatar Jiri Kosina
Browse files

Merge branch 'for-6.5/core' into for-linus

- more bullet-proof handling of devres-managed resources in HID core
  (Dmitry Torokhov)
- kunit test Kconfig dependency fix (Geert Uytterhoeven)
parents e80b5003 49904a0e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+71 −47
Original line number Diff line number Diff line
@@ -2587,48 +2587,41 @@ bool hid_compare_device_paths(struct hid_device *hdev_a,
}
EXPORT_SYMBOL_GPL(hid_compare_device_paths);

static int hid_device_probe(struct device *dev)
static bool hid_check_device_match(struct hid_device *hdev,
				   struct hid_driver *hdrv,
				   const struct hid_device_id **id)
{
	struct hid_driver *hdrv = to_hid_driver(dev->driver);
	struct hid_device *hdev = to_hid_device(dev);
	const struct hid_device_id *id;
	int ret = 0;

	if (down_interruptible(&hdev->driver_input_lock)) {
		ret = -EINTR;
		goto end;
	}
	hdev->io_started = false;

	clear_bit(ffs(HID_STAT_REPROBED), &hdev->status);
	*id = hid_match_device(hdev, hdrv);
	if (!*id)
		return false;

	if (!hdev->driver) {
		id = hid_match_device(hdev, hdrv);
		if (id == NULL) {
			ret = -ENODEV;
			goto unlock;
		}
	if (hdrv->match)
		return hdrv->match(hdev, hid_ignore_special_drivers);

		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.
	 * 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.
	 */
			if (hid_ignore_special_drivers) {
				ret = -ENODEV;
				goto unlock;
			}
	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 */
@@ -2636,15 +2629,42 @@ static int hid_device_probe(struct device *dev)
		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;
}
unlock:

static int hid_device_probe(struct device *dev)
{
	struct hid_device *hdev = to_hid_device(dev);
	struct hid_driver *hdrv = to_hid_driver(dev->driver);
	int ret = 0;

	if (down_interruptible(&hdev->driver_input_lock))
		return -EINTR;

	hdev->io_started = false;
	clear_bit(ffs(HID_STAT_REPROBED), &hdev->status);

	if (!hdev->driver)
		ret = __hid_device_probe(hdev, hdrv);

	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;
	}
+1 −0
Original line number Diff line number Diff line
@@ -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;