diff mbox series

[resend,2] HID: allow specifying quirks params for hid-core

Message ID 5d84881e-e855-9eb0-7e88-752010136715@polimi.it
State New
Headers show
Series [resend,2] HID: allow specifying quirks params for hid-core | expand

Commit Message

Marco Morandini Aug. 29, 2023, 2:48 p.m. UTC
Before this patch it was possible to specify quirks
    using run-time parameters, but only for the usbhid module.
    This patch introduces a quirks parameter for hid-core
    allowing to specify quirks as
    hid.quirks=BUS:vendorID:productID:quirks

    Signed-off-by: Marco Morandini <marco.morandini@polimi.it>
---
I don't know if this is a good idea or not.

If it was for me, I'd get rid of the usbhid parameters
and of the duplicated hid_quirks_init,
forcing everyone to specify the bus,
but I fear this could be a regression for user space.


 drivers/hid/hid-core.c   | 13 +++++++++++++
 drivers/hid/hid-quirks.c | 33 +++++++++++++++++++++++++++++++++
 include/linux/hid.h      |  1 +
 3 files changed, 47 insertions(+)
diff mbox series

Patch

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 22623eb4f72f..e1bdba978dbc 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -45,6 +45,13 @@  static int hid_ignore_special_drivers = 0;
 module_param_named(ignore_special_drivers, hid_ignore_special_drivers, int, 0600);
 MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle all devices by generic driver");
 
+/* Quirks specified at module load time */
+static char *quirks_param[MAX_USBHID_BOOT_QUIRKS];
+module_param_array_named(quirks, quirks_param, charp, NULL, 0444);
+MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
+		" quirks=BUS:vendorID:productID:quirks"
+		" where BUS, vendorID, productID, and quirks are all in"
+		" 0x-prefixed hex");
 /*
  * Register a new report for a device.
  */
@@ -2951,6 +2958,10 @@  static int __init hid_init(void)
 {
 	int ret;
 
+	ret = hid_quirks_bus_init(quirks_param, MAX_USBHID_BOOT_QUIRKS);
+	if (ret)
+		goto usbhid_quirks_init_fail;
+
 	ret = bus_register(&hid_bus_type);
 	if (ret) {
 		pr_err("can't register hid bus\n");
@@ -2972,6 +2983,8 @@  static int __init hid_init(void)
 	bus_unregister(&hid_bus_type);
 err:
 	return ret;
+usbhid_quirks_init_fail:
+	return ret;
 }
 
 static void __exit hid_exit(void)
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 3983b4f282f8..40d3ba78ff73 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -1182,6 +1182,39 @@  static void hid_remove_all_dquirks(__u16 bus)
 
 }
 
+
+/**
+ * hid_quirks_bus_init - apply HID quirks specified at module load time
+ * @quirks_param: array of quirks strings (bus:vendor:product:quirks)
+ * @count: number of quirks to check
+ */
+int hid_quirks_bus_init(char **quirks_param, int count)
+{
+	struct hid_device_id id = { 0 };
+	int n = 0, m;
+	unsigned short int bus, vendor, product;
+	u32 quirks;
+
+	for (; n < count && quirks_param[n]; n++) {
+
+		m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%hx:0x%x",
+				&bus, &vendor, &product, &quirks);
+
+		id.bus =  (__u16)bus;
+		id.vendor = (__u16)vendor;
+		id.product = (__u16)product;
+
+		if (m != 4 ||
+		    hid_modify_dquirk(&id, quirks) != 0) {
+			pr_warn("Could not parse HID quirk module param %s\n",
+				quirks_param[n]);
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(hid_quirks_bus_init);
+
 /**
  * hid_quirks_init - apply HID quirks specified at module load time
  * @quirks_param: array of quirks strings (vendor:product:quirks)
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 4e4c4fe36911..7f2e8ba7d783 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -1178,6 +1178,7 @@  int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
 
 /* HID quirks API */
 unsigned long hid_lookup_quirk(const struct hid_device *hdev);
+int hid_quirks_bus_init(char **quirks_param, int count);
 int hid_quirks_init(char **quirks_param, __u16 bus, int count);
 void hid_quirks_exit(__u16 bus);