mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-04 04:40:25 +01:00
quirks: allow for parsing multiple products
This allows for a slight optimization of the quirks parser: where multiple devices from the same vendor require the same quirk, allow for multiple product matches in the form: MatchProduct=0x0001;0x0002; This is stored as a fixed-sized zero-terminated array - a product ID of zero isn't something we need to worry about in real situations. Closes #879 Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1038>
This commit is contained in:
parent
ea7ad8d25c
commit
f159abdc57
2 changed files with 78 additions and 10 deletions
41
src/quirks.c
41
src/quirks.c
|
|
@ -141,7 +141,7 @@ struct match {
|
|||
char *uniq;
|
||||
enum bustype bus;
|
||||
uint32_t vendor;
|
||||
uint32_t product;
|
||||
uint32_t product[64]; /* zero-terminated */
|
||||
uint32_t version;
|
||||
|
||||
char *dmi; /* dmi modalias with preceding "dmi:" */
|
||||
|
|
@ -537,6 +537,14 @@ parse_hex(const char *value, unsigned int *parsed)
|
|||
*parsed <= 0xFFFF;
|
||||
}
|
||||
|
||||
static int
|
||||
strv_parse_hex(const char *str, size_t index, void *data)
|
||||
{
|
||||
unsigned int *product = data;
|
||||
|
||||
return !parse_hex(str, &product[index]); /* 0 for success */
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a MatchFooBar=banana line.
|
||||
*
|
||||
|
|
@ -592,13 +600,18 @@ parse_match(struct quirks_context *ctx,
|
|||
|
||||
s->match.vendor = vendor;
|
||||
} else if (streq(key, "MatchProduct")) {
|
||||
unsigned int product;
|
||||
unsigned int product[ARRAY_LENGTH(s->match.product)] = {0};
|
||||
const size_t max = ARRAY_LENGTH(s->match.product) - 1;
|
||||
|
||||
check_set_bit(s, M_PID);
|
||||
if (!parse_hex(value, &product))
|
||||
size_t nelems = 0;
|
||||
char **strs = strv_from_string(value, ";", &nelems);
|
||||
int rc = strv_for_each_n((const char**)strs, max, strv_parse_hex, product);
|
||||
strv_free(strs);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
s->match.product = product;
|
||||
check_set_bit(s, M_PID);
|
||||
memcpy(s->match.product, product, sizeof(product));
|
||||
} else if (streq(key, "MatchVersion")) {
|
||||
unsigned int version;
|
||||
|
||||
|
|
@ -1325,7 +1338,8 @@ match_fill_bus_vid_pid(struct match *m,
|
|||
if (sscanf(str, "%x/%x/%x/%x", &bus, &vendor, &product, &version) != 4)
|
||||
return;
|
||||
|
||||
m->product = product;
|
||||
m->product[0] = product;
|
||||
m->product[1] = 0;
|
||||
m->vendor = vendor;
|
||||
m->version = version;
|
||||
m->bits |= M_PID|M_VID|M_VERSION;
|
||||
|
|
@ -1545,8 +1559,19 @@ quirk_match_section(struct quirks_context *ctx,
|
|||
matched_flags |= flag;
|
||||
break;
|
||||
case M_PID:
|
||||
if (m->product == s->match.product)
|
||||
matched_flags |= flag;
|
||||
ARRAY_FOR_EACH(m->product, mi) {
|
||||
if (*mi == 0 || matched_flags & flag)
|
||||
break;
|
||||
|
||||
ARRAY_FOR_EACH(s->match.product, si) {
|
||||
if (*si == 0)
|
||||
break;
|
||||
if (*mi == *si) {
|
||||
matched_flags |= flag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case M_VERSION:
|
||||
if (m->version == s->match.version)
|
||||
|
|
|
|||
|
|
@ -581,11 +581,11 @@ START_TEST(quirks_parse_product)
|
|||
struct quirks_context *ctx;
|
||||
const char quirks_file[] =
|
||||
"[Section name]\n"
|
||||
"MatchProduct=0x0000\n"
|
||||
"MatchProduct=0x12AB\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchProduct=0x0001\n"
|
||||
"MatchProduct=0x0001;0x1234;0xABCD\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
|
|
@ -604,6 +604,48 @@ START_TEST(quirks_parse_product)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(quirks_parse_product_too_many)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
const char prologue[] =
|
||||
"[Section name]\n"
|
||||
"MatchProduct=0x12AB\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchProduct=";
|
||||
const char epilogue[] = "\n"
|
||||
"ModelAppleTouchpad=1\n"
|
||||
"\n"
|
||||
"[Section name]\n"
|
||||
"MatchProduct=0x2343\n"
|
||||
"ModelAppleTouchpad=1\n";
|
||||
|
||||
char matches[4096] = {0};
|
||||
|
||||
for (int i = 0; i < 128; i++) {
|
||||
int len = strlen(matches);
|
||||
int remaining = sizeof(matches) - len;
|
||||
snprintf(&matches[len], remaining, "0x%04X", i);
|
||||
}
|
||||
|
||||
char *quirks_file = NULL;
|
||||
xasprintf(&quirks_file, "%s%s%s", prologue, matches, epilogue);
|
||||
struct data_dir dd = make_data_dir(quirks_file);
|
||||
|
||||
free(quirks_file);
|
||||
|
||||
/* This test will only blow up in valgrind/asan */
|
||||
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_product_invalid)
|
||||
{
|
||||
struct quirks_context *ctx;
|
||||
|
|
@ -1590,6 +1632,7 @@ TEST_COLLECTION(quirks)
|
|||
litest_add_deviceless(quirks_parse_vendor);
|
||||
litest_add_deviceless(quirks_parse_vendor_invalid);
|
||||
litest_add_deviceless(quirks_parse_product);
|
||||
litest_add_deviceless(quirks_parse_product_too_many);
|
||||
litest_add_deviceless(quirks_parse_product_invalid);
|
||||
litest_add_deviceless(quirks_parse_version);
|
||||
litest_add_deviceless(quirks_parse_version_invalid);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue