diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2024-05-28 16:00:25 +1000 |
---|---|---|
committer | Marge Bot <emma+marge@anholt.net> | 2024-06-05 11:35:59 +0000 |
commit | a2f0cc35c59335deb216f97f0f881813b0249424 (patch) | |
tree | fe417fe3f48dcd090f0ac8235201b5500a0f8771 | |
parent | e72ee0b1c8f3ba1434e5b4cc163943f7de1a1d19 (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.c | 38 | ||||
-rw-r--r-- | test/test-quirks.c | 65 |
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); |