summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2024-05-28 16:00:25 +1000
committerMarge Bot <emma+marge@anholt.net>2024-06-05 11:35:59 +0000
commita2f0cc35c59335deb216f97f0f881813b0249424 (patch)
treefe417fe3f48dcd090f0ac8235201b5500a0f8771
parente72ee0b1c8f3ba1434e5b4cc163943f7de1a1d19 (diff)
quirks: add support for Uniq matching
Same as MatchName but matches on the UNIQ udev property instead. This is needed for some Huion, Gaomon and other tablet devices that only differentiate each other through the Uniq string which contains the firmware version. Closes #997 Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1006>
-rw-r--r--src/quirks.c38
-rw-r--r--test/test-quirks.c65
2 files changed, 102 insertions, 1 deletions
diff --git a/src/quirks.c b/src/quirks.c
index 0fbd53f2..01065d5e 100644
--- a/src/quirks.c
+++ b/src/quirks.c
@@ -103,8 +103,9 @@ enum match_flags {
M_UDEV_TYPE = bit(5),
M_DT = bit(6),
M_VERSION = bit(7),
+ M_UNIQ = bit(8),
- M_LAST = M_VERSION,
+ M_LAST = M_UNIQ,
};
enum bustype {
@@ -137,6 +138,7 @@ struct match {
uint32_t bits;
char *name;
+ char *uniq;
enum bustype bus;
uint32_t vendor;
uint32_t product;
@@ -307,6 +309,7 @@ matchflagname(enum match_flags f)
case M_DMI: return "MatchDMIModalias"; break;
case M_UDEV_TYPE: return "MatchUdevType"; break;
case M_DT: return "MatchDeviceTree"; break;
+ case M_UNIQ: return "MatchUniq"; break;
default:
abort();
}
@@ -512,6 +515,7 @@ section_destroy(struct section *s)
free(s->name);
free(s->match.name);
+ free(s->match.uniq);
free(s->match.dmi);
free(s->match.dt);
@@ -560,6 +564,9 @@ parse_match(struct quirks_context *ctx,
if (streq(key, "MatchName")) {
check_set_bit(s, M_NAME);
s->match.name = safe_strdup(value);
+ } else if (streq(key, "MatchUniq")) {
+ check_set_bit(s, M_UNIQ);
+ s->match.uniq = safe_strdup(value);
} else if (streq(key, "MatchBus")) {
check_set_bit(s, M_BUS);
if (streq(value, "usb"))
@@ -1280,6 +1287,29 @@ match_fill_name(struct match *m,
}
static inline void
+match_fill_uniq(struct match *m,
+ struct udev_device *device)
+{
+ const char *str = udev_prop(device, "UNIQ");
+ size_t slen;
+
+ if (!str)
+ return;
+
+ /* udev uniq is in quotes, strip them */
+ if (str[0] == '"')
+ str++;
+
+ m->uniq = safe_strdup(str);
+ slen = strlen(m->uniq);
+ if (slen > 1 &&
+ m->uniq[slen - 1] == '"')
+ m->uniq[slen - 1] = '\0';
+
+ m->bits |= M_UNIQ;
+}
+
+static inline void
match_fill_bus_vid_pid(struct match *m,
struct udev_device *device)
{
@@ -1375,6 +1405,7 @@ match_new(struct udev_device *device,
struct match *m = zalloc(sizeof *m);
match_fill_name(m, device);
+ match_fill_uniq(m, device);
match_fill_bus_vid_pid(m, device);
match_fill_dmi_dt(m, dmi, dt);
match_fill_udev_type(m, device);
@@ -1386,6 +1417,7 @@ match_free(struct match *m)
{
/* dmi and dt are global */
free(m->name);
+ free(m->uniq);
free(m);
}
@@ -1500,6 +1532,10 @@ quirk_match_section(struct quirks_context *ctx,
if (fnmatch(s->match.name, m->name, 0) == 0)
matched_flags |= flag;
break;
+ case M_UNIQ:
+ if (fnmatch(s->match.uniq, m->uniq, 0) == 0)
+ matched_flags |= flag;
+ break;
case M_BUS:
if (m->bus == s->match.bus)
matched_flags |= flag;
diff --git a/test/test-quirks.c b/test/test-quirks.c
index 85c4792f..a1bb214f 100644
--- a/test/test-quirks.c
+++ b/test/test-quirks.c
@@ -759,6 +759,69 @@ START_TEST(quirks_parse_name_invalid)
}
END_TEST
+START_TEST(quirks_parse_uniq)
+{
+ struct quirks_context *ctx;
+ const char quirks_file[] =
+ "[Section Uniq]\n"
+ "MatchUniq=1235\n"
+ "ModelAppleTouchpad=1\n"
+ "\n"
+ "[Section Uniq]\n"
+ "MatchUniq=abc\n"
+ "ModelAppleTouchpad=1\n"
+ "\n"
+ "[Section Uniq]\n"
+ "MatchUniq=*foo\n"
+ "ModelAppleTouchpad=1\n"
+ "\n"
+ "[Section Uniq]\n"
+ "MatchUniq=foo*\n"
+ "ModelAppleTouchpad=1\n"
+ "\n"
+ "[Section Uniq]\n"
+ "MatchUniq=foo[]\n"
+ "ModelAppleTouchpad=1\n"
+ "\n"
+ "[Section Uniq]\n"
+ "MatchUniq=*foo*\n"
+ "ModelAppleTouchpad=1\n";
+ struct data_dir dd = make_data_dir(quirks_file);
+
+ ctx = quirks_init_subsystem(dd.dirname,
+ NULL,
+ log_handler,
+ NULL,
+ QLOG_CUSTOM_LOG_PRIORITIES);
+ ck_assert_notnull(ctx);
+ quirks_context_unref(ctx);
+ cleanup_data_dir(dd);
+}
+END_TEST
+
+START_TEST(quirks_parse_uniq_invalid)
+{
+ struct quirks_context *ctx;
+ const char *quirks_file[] = {
+ "[Section name]\n"
+ "MatchUniq=\n"
+ "ModelAppleTouchpad=1\n",
+ };
+
+ ARRAY_FOR_EACH(quirks_file, qf) {
+ struct data_dir dd = make_data_dir(*qf);
+
+ ctx = quirks_init_subsystem(dd.dirname,
+ NULL,
+ log_handler,
+ NULL,
+ QLOG_CUSTOM_LOG_PRIORITIES);
+ ck_assert(ctx == NULL);
+ cleanup_data_dir(dd);
+ }
+}
+END_TEST
+
START_TEST(quirks_parse_udev)
{
struct quirks_context *ctx;
@@ -1532,6 +1595,8 @@ TEST_COLLECTION(quirks)
litest_add_deviceless(quirks_parse_version_invalid);
litest_add_deviceless(quirks_parse_name);
litest_add_deviceless(quirks_parse_name_invalid);
+ litest_add_deviceless(quirks_parse_uniq);
+ litest_add_deviceless(quirks_parse_uniq_invalid);
litest_add_deviceless(quirks_parse_udev);
litest_add_deviceless(quirks_parse_udev_invalid);
litest_add_deviceless(quirks_parse_dmi);