diff --git a/src/quirks.c b/src/quirks.c index 3f133015..b1be3d57 100644 --- a/src/quirks.c +++ b/src/quirks.c @@ -85,8 +85,9 @@ enum match_flags { M_DMI = (1 << 4), M_UDEV_TYPE = (1 << 5), M_DT = (1 << 6), + M_VERSION = (1 << 7), - M_LAST = M_DT, + M_LAST = M_VERSION, }; enum bustype { @@ -121,6 +122,7 @@ struct match { enum bustype bus; uint32_t vendor; uint32_t product; + uint32_t version; char *dmi; /* dmi modalias with preceding "dmi:" */ @@ -275,6 +277,7 @@ matchflagname(enum match_flags f) case M_BUS: return "MatchBus"; break; case M_VID: return "MatchVendor"; break; case M_PID: return "MatchProduct"; break; + case M_VERSION: return "MatchVersion"; break; case M_DMI: return "MatchDMIModalias"; break; case M_UDEV_TYPE: return "MatchUdevType"; break; case M_DT: return "MatchDeviceTree"; break; @@ -489,6 +492,16 @@ parse_match(struct quirks_context *ctx, goto out; s->match.product = product; + } else if (streq(key, "MatchVersion")) { + unsigned int version; + + check_set_bit(s, M_VERSION); + if (!strneq(value, "0x", 2) || + !safe_atou_base(value, &version, 16) || + version > 0xFFFF) + goto out; + + s->match.version = version; } else if (streq(key, "MatchDMIModalias")) { check_set_bit(s, M_DMI); if (!strneq(value, "dmi:", 4)) { @@ -1147,7 +1160,8 @@ match_fill_bus_vid_pid(struct match *m, m->product = product; m->vendor = vendor; - m->bits |= M_PID|M_VID; + m->version = version; + m->bits |= M_PID|M_VID|M_VERSION; switch (bus) { case BUS_USB: m->bus = BT_USB; @@ -1295,6 +1309,10 @@ quirk_match_section(struct quirks_context *ctx, if (m->product == s->match.product) matched_flags |= flag; break; + case M_VERSION: + if (m->version == s->match.version) + matched_flags |= flag; + break; case M_DMI: if (fnmatch(s->match.dmi, m->dmi, 0) == 0) matched_flags |= flag; diff --git a/test/test-quirks.c b/test/test-quirks.c index 16bbacf0..be488a7e 100644 --- a/test/test-quirks.c +++ b/test/test-quirks.c @@ -578,6 +578,67 @@ START_TEST(quirks_parse_product_invalid) } END_TEST +START_TEST(quirks_parse_version) +{ + struct quirks_context *ctx; + const char quirks_file[] = + "[Section name]\n" + "MatchVersion=0x0000\n" + "ModelAppleTouchpad=1\n" + "\n" + "[Section name]\n" + "MatchVersion=0x0001\n" + "ModelAppleTouchpad=1\n" + "\n" + "[Section name]\n" + "MatchVersion=0x2343\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_version_invalid) +{ + struct quirks_context *ctx; + const char *quirks_file[] = { + "[Section name]\n" + "MatchVersion=-1\n" + "ModelAppleTouchpad=1\n", + "[Section name]\n" + "MatchVersion=abc\n" + "ModelAppleTouchpad=1\n", + "[Section name]\n" + "MatchVersion=0xFFFFF\n" + "ModelAppleTouchpad=1\n", + "[Section name]\n" + "MatchVersion=123\n" + "ModelAppleTouchpad=1\n", + }; + const char **qf; + + 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_name) { struct quirks_context *ctx; @@ -939,6 +1000,8 @@ TEST_COLLECTION(quirks) litest_add_for_device("quirks:parsing", quirks_parse_vendor_invalid, LITEST_MOUSE); litest_add_for_device("quirks:parsing", quirks_parse_product, LITEST_MOUSE); litest_add_for_device("quirks:parsing", quirks_parse_product_invalid, LITEST_MOUSE); + litest_add_for_device("quirks:parsing", quirks_parse_version, LITEST_MOUSE); + litest_add_for_device("quirks:parsing", quirks_parse_version_invalid, LITEST_MOUSE); litest_add_for_device("quirks:parsing", quirks_parse_name, LITEST_MOUSE); litest_add_for_device("quirks:parsing", quirks_parse_name_invalid, LITEST_MOUSE); litest_add_for_device("quirks:parsing", quirks_parse_udev, LITEST_MOUSE);