linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
To: "Jiri Kosina" <jikos@kernel.org>,
	"Dmitry Torokhov" <dmitry.torokhov@gmail.com>,
	"Jonathan Corbet" <corbet@lwn.net>,
	"Ahelenia Ziemiańska" <nabijaczleweli@nabijaczleweli.xyz>,
	"Ping Cheng" <pinglinux@gmail.com>,
	"Aaron Armstrong Skomra" <skomra@gmail.com>,
	"Jason Gerecke" <killertofu@gmail.com>,
	"Peter Hutterer" <peter.hutterer@who-t.net>
Cc: linux-input@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	Benjamin Tissoires <benjamin.tissoires@redhat.com>
Subject: [PATCH v2 07/12] HID: compute an ordered list of input fields to process
Date: Thu,  3 Feb 2022 15:32:21 +0100	[thread overview]
Message-ID: <20220203143226.4023622-8-benjamin.tissoires@redhat.com> (raw)
In-Reply-To: <20220203143226.4023622-1-benjamin.tissoires@redhat.com>

This will be used in a later commit:
we build a list of input fields (and usage_index) that is ordered based
on a usage priority.

Changing the usage priority allows to re-order the processed list, meaning
that we can enforce some usages to be process before others.

For instance, before processing InRange in the HID tablets, we need to
know if we are using the eraser (side or button). Enforcing a higher
(lower number) priority for Invert allows to force the input stack to
process that field before.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/hid-core.c | 105 ++++++++++++++++++++++++++++++++++++++++-
 include/linux/hid.h    |  10 ++++
 2 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 34188d7ac0f7..b38528118642 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -81,6 +81,7 @@ struct hid_report *hid_register_report(struct hid_device *device,
 	report_enum->report_id_hash[id] = report;
 
 	list_add_tail(&report->list, &report_enum->report_list);
+	INIT_LIST_HEAD(&report->field_entry_list);
 
 	return report;
 }
@@ -101,7 +102,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
 
 	field = kzalloc((sizeof(struct hid_field) +
 			 usages * sizeof(struct hid_usage) +
-			 2 * usages * sizeof(unsigned int)), GFP_KERNEL);
+			 3 * usages * sizeof(unsigned int)), GFP_KERNEL);
 	if (!field)
 		return NULL;
 
@@ -110,6 +111,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
 	field->usage = (struct hid_usage *)(field + 1);
 	field->value = (s32 *)(field->usage + usages);
 	field->new_value = (s32 *)(field->value + usages);
+	field->usages_priorities = (s32 *)(field->new_value + usages);
 	field->report = report;
 
 	return field;
@@ -657,6 +659,8 @@ static void hid_free_report(struct hid_report *report)
 {
 	unsigned n;
 
+	kfree(report->field_entries);
+
 	for (n = 0; n < report->maxfield; n++)
 		kfree(report->field[n]);
 	kfree(report);
@@ -1667,6 +1671,103 @@ static void hid_process_report(struct hid_device *hid,
 	}
 }
 
+/*
+ * Insert a given usage_index in a field in the list
+ * of processed usages in the report.
+ *
+ * The elements of lower priority score are processed
+ * first.
+ */
+static void __hid_insert_field_entry(struct hid_device *hid,
+				     struct hid_report *report,
+				     struct hid_field_entry *entry,
+				     struct hid_field *field,
+				     unsigned int usage_index)
+{
+	struct hid_field_entry *next;
+
+	entry->field = field;
+	entry->index = usage_index;
+	entry->priority = field->usages_priorities[usage_index];
+
+	/* insert the element at the correct position */
+	list_for_each_entry(next,
+			    &report->field_entry_list,
+			    list) {
+		/*
+		 * the priority of our element is strictly higher
+		 * than the next one, insert it before
+		 */
+		if (entry->priority > next->priority) {
+			list_add_tail(&entry->list, &next->list);
+			return;
+		}
+	}
+
+	/* lowest priority score: insert at the end */
+	list_add_tail(&entry->list, &report->field_entry_list);
+}
+
+static void hid_report_process_ordering(struct hid_device *hid,
+					struct hid_report *report)
+{
+	struct hid_field *field;
+	struct hid_field_entry *entries;
+	unsigned int a, u, usages;
+	unsigned int count = 0;
+
+	/* count the number of individual fields in the report */
+	for (a = 0; a < report->maxfield; a++) {
+		field = report->field[a];
+
+		if (field->flags & HID_MAIN_ITEM_VARIABLE)
+			count += field->report_count;
+		else
+			count++;
+	}
+
+	/* allocate the memory to process the fields */
+	entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
+	if (!entries)
+		return;
+
+	report->field_entries = entries;
+
+	/*
+	 * walk through all fields in the report and
+	 * store them by priority order in report->field_entry_list
+	 *
+	 * - Var elements are individualized (field + usage_index)
+	 * - Arrays are taken as one, we can not chose an order for them
+	 */
+	usages = 0;
+	for (a = 0; a < report->maxfield; a++) {
+		field = report->field[a];
+
+		if (field->flags & HID_MAIN_ITEM_VARIABLE) {
+			for (u = 0; u < field->report_count; u++) {
+				__hid_insert_field_entry(hid, report,
+							 &entries[usages],
+							 field, u);
+				usages++;
+			}
+		} else {
+			__hid_insert_field_entry(hid, report, &entries[usages],
+						 field, 0);
+			usages++;
+		}
+	}
+}
+
+static void hid_process_ordering(struct hid_device *hid)
+{
+	struct hid_report *report;
+	struct hid_report_enum *report_enum = &hid->report_enum[HID_INPUT_REPORT];
+
+	list_for_each_entry(report, &report_enum->report_list, list)
+		hid_report_process_ordering(hid, report);
+}
+
 /*
  * Output the field into the report.
  */
@@ -2050,6 +2151,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
 		return -ENODEV;
 	}
 
+	hid_process_ordering(hdev);
+
 	if ((hdev->claimed & HID_CLAIMED_INPUT) &&
 			(connect_mask & HID_CONNECT_FF) && hdev->ff_init)
 		hdev->ff_init(hdev);
diff --git a/include/linux/hid.h b/include/linux/hid.h
index cf79eb3da465..f25020c0d6b8 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -477,6 +477,7 @@ struct hid_field {
 	unsigned  report_type;		/* (input,output,feature) */
 	__s32    *value;		/* last known value(s) */
 	__s32    *new_value;		/* newly read value(s) */
+	__s32    *usages_priorities;	/* priority of each usage when reading the report */
 	__s32     logical_minimum;
 	__s32     logical_maximum;
 	__s32     physical_minimum;
@@ -493,13 +494,22 @@ struct hid_field {
 
 #define HID_MAX_FIELDS 256
 
+struct hid_field_entry {
+	struct list_head list;
+	struct hid_field *field;
+	unsigned int index;
+	__s32 priority;
+};
+
 struct hid_report {
 	struct list_head list;
 	struct list_head hidinput_list;
+	struct list_head field_entry_list;		/* ordered list of input fields */
 	unsigned int id;				/* id of this report */
 	unsigned int type;				/* report type */
 	unsigned int application;			/* application usage for this report */
 	struct hid_field *field[HID_MAX_FIELDS];	/* fields of the report */
+	struct hid_field_entry *field_entries;		/* allocated memory of input field_entry */
 	unsigned maxfield;				/* maximum valid field index */
 	unsigned size;					/* size of the report (bits) */
 	struct hid_device *device;			/* associated device */
-- 
2.33.1


  parent reply	other threads:[~2022-02-03 14:33 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-03 14:32 [PATCH v2 00/12] HID: fix for generic input processing Benjamin Tissoires
2022-02-03 14:32 ` [PATCH v2 01/12] HID: core: statically allocate read buffers Benjamin Tissoires
2022-02-03 14:32 ` [PATCH v2 02/12] HID: core: de-duplicate some code in hid_input_field() Benjamin Tissoires
2022-02-03 14:32 ` [PATCH v2 03/12] HID: core: split data fetching from processing " Benjamin Tissoires
2022-02-03 14:32 ` [PATCH v2 04/12] HID: input: tag touchscreens as such if the physical is not there Benjamin Tissoires
2022-02-03 14:32 ` [PATCH v2 05/12] HID: input: rework spaghetti code with switch statements Benjamin Tissoires
2022-02-03 14:32 ` [PATCH v2 06/12] HID: input: move up out-of-range processing of input values Benjamin Tissoires
2022-02-03 14:32 ` Benjamin Tissoires [this message]
2022-02-03 14:32 ` [PATCH v2 08/12] HID: core: for input reports, process the usages by priority list Benjamin Tissoires
2022-02-03 14:32 ` [PATCH v2 09/12] HID: input: enforce Invert usage to be processed before InRange Benjamin Tissoires
2022-02-03 14:32 ` [PATCH v2 10/12] HID: input: remove the need for HID_QUIRK_INVERT Benjamin Tissoires
2022-02-04  1:41   ` Ping Cheng
2022-02-10  5:21   ` Ping Cheng
2022-02-10  5:43     ` Ping Cheng
2022-02-14 10:23       ` Benjamin Tissoires
2022-02-15  2:04         ` Ping Cheng
2022-02-15  8:51           ` Benjamin Tissoires
2022-02-16 12:42             ` Benjamin Tissoires
2022-02-17  1:27               ` Ping Cheng
2022-02-03 14:32 ` [PATCH v2 11/12] HID: input: accommodate priorities for slotted devices Benjamin Tissoires
2022-02-03 14:32 ` [PATCH v2 12/12] Input: docs: add more details on the use of BTN_TOOL Benjamin Tissoires
2022-02-16  5:40   ` Peter Hutterer
2022-03-01 14:53 ` [PATCH v2 00/12] HID: fix for generic input processing Jiri Kosina

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220203143226.4023622-8-benjamin.tissoires@redhat.com \
    --to=benjamin.tissoires@redhat.com \
    --cc=corbet@lwn.net \
    --cc=dmitry.torokhov@gmail.com \
    --cc=jikos@kernel.org \
    --cc=killertofu@gmail.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nabijaczleweli@nabijaczleweli.xyz \
    --cc=peter.hutterer@who-t.net \
    --cc=pinglinux@gmail.com \
    --cc=skomra@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).