xref: /freebsd/usr.sbin/moused/moused/quirks.c (revision aef807876c305587c60f73e2cd914115d22a53fd)
1 /*
2  * Copyright © 2018 Red Hat, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /* This has the hallmarks of a library to make it re-usable from the tests
25  * and from the list-quirks tool. It doesn't have all of the features from a
26  * library you'd expect though
27  */
28 
29 #include <sys/types.h>
30 #include <dev/evdev/input.h>
31 
32 #undef NDEBUG /* You don't get to disable asserts here */
33 #include <assert.h>
34 #include <dirent.h>
35 #include <errno.h>
36 #include <fnmatch.h>
37 #include <kenv.h>
38 #include <libgen.h>
39 #include <limits.h>
40 #include <stdarg.h>
41 #include <stdbool.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 
46 #include "quirks.h"
47 #include "util.h"
48 #include "util-list.h"
49 
50 
51 /* Custom logging so we can have detailed output for the tool but minimal
52  * logging for moused itself. */
53 #define qlog_debug(ctx_, ...) quirk_log_msg((ctx_), QLOG_NOISE, __VA_ARGS__)
54 #define qlog_info(ctx_, ...) quirk_log_msg((ctx_),  QLOG_INFO, __VA_ARGS__)
55 #define qlog_error(ctx_, ...) quirk_log_msg((ctx_), QLOG_ERROR, __VA_ARGS__)
56 #define qlog_parser(ctx_, ...) quirk_log_msg((ctx_), QLOG_PARSER_ERROR, __VA_ARGS__)
57 
58 enum property_type {
59 	PT_UINT,
60 	PT_INT,
61 	PT_STRING,
62 	PT_BOOL,
63 	PT_DIMENSION,
64 	PT_RANGE,
65 	PT_DOUBLE,
66 	PT_TUPLES,
67 	PT_UINT_ARRAY,
68 };
69 
70 struct quirk_array {
71 	union {
72 		uint32_t u[32];
73 	} data;
74 	size_t nelements;
75 };
76 
77 /**
78  * Generic value holder for the property types we support. The type
79  * identifies which value in the union is defined and we expect callers to
80  * already know which type yields which value.
81  */
82 struct property {
83 	size_t refcount;
84 	struct list link; /* struct sections.properties */
85 
86 	enum quirk id;
87 	enum property_type type;
88 	union {
89 		bool b;
90 		uint32_t u;
91 		int32_t i;
92 		char *s;
93 		double d;
94 		struct quirk_dimensions dim;
95 		struct quirk_range range;
96 		struct quirk_tuples tuples;
97 		struct quirk_array array;
98 	} value;
99 };
100 
101 enum match_flags {
102 	M_NAME		= bit(0),
103 	M_BUS		= bit(1),
104 	M_VID		= bit(2),
105 	M_PID		= bit(3),
106 	M_DMI		= bit(4),
107 	M_UDEV_TYPE	= bit(5),
108 	M_DT		= bit(6),
109 	M_VERSION	= bit(7),
110 	M_UNIQ          = bit(8),
111 
112 	M_LAST		= M_UNIQ,
113 };
114 
115 enum bustype {
116 	BT_UNKNOWN,
117 	BT_USB,
118 	BT_BLUETOOTH,
119 	BT_PS2,
120 	BT_RMI,
121 	BT_I2C,
122 	BT_SPI,
123 };
124 
125 enum udev_type {
126 	UDEV_MOUSE		= bit(1),
127 	UDEV_POINTINGSTICK	= bit(2),
128 	UDEV_TOUCHPAD		= bit(3),
129 	UDEV_TABLET		= bit(4),
130 	UDEV_TABLET_PAD		= bit(5),
131 	UDEV_JOYSTICK		= bit(6),
132 	UDEV_KEYBOARD		= bit(7),
133 };
134 
135 /**
136  * Contains the combined set of matches for one section or the values for
137  * one device.
138  *
139  * bits defines which fields are set, the rest is zero.
140  */
141 struct match {
142 	uint32_t bits;
143 
144 	char *name;
145 	char *uniq;
146 	enum bustype bus;
147 	uint32_t vendor;
148 	uint32_t product[64]; /* zero-terminated */
149 	uint32_t version;
150 
151 	char *dmi;	/* dmi modalias with preceding "dmi:" */
152 
153 	/* We can have more than one type set, so this is a bitfield */
154 	uint32_t udev_type;
155 
156 	char *dt;	/* device tree compatible (first) string */
157 };
158 
159 /**
160  * Represents one section in the .quirks file.
161  */
162 struct section {
163 	struct list link;
164 
165 	bool has_match;		/* to check for empty sections */
166 	bool has_property;	/* to check for empty sections */
167 
168 	char *name;		/* the [Section Name] */
169 	struct match match;
170 	struct list properties;
171 };
172 
173 /**
174  * The struct returned to the caller. It contains the
175  * properties for a given device.
176  */
177 struct quirks {
178 	size_t refcount;
179 	struct list link; /* struct quirks_context.quirks */
180 
181 	/* These are not ref'd, just a collection of pointers */
182 	struct property **properties;
183 	size_t nproperties;
184 
185 	/* Special properties for AttrEventCode and AttrInputCode, these are
186 	 * owned by us, not the section */
187 	struct list floating_properties;
188 };
189 
190 /**
191  * Quirk matching context, initialized once with quirks_init_subsystem()
192  */
193 struct quirks_context {
194 	size_t refcount;
195 
196 	moused_log_handler *log_handler;
197 	enum quirks_log_type log_type;
198 
199 	char *dmi;
200 	char *dt;
201 
202 	struct list sections;
203 
204 	/* list of quirks handed to moused, just for bookkeeping */
205 	struct list quirks;
206 };
207 
208 MOUSED_ATTRIBUTE_PRINTF(3, 0)
209 static inline void
quirk_log_msg_va(struct quirks_context * ctx,enum quirks_log_priorities priority,const char * format,va_list args)210 quirk_log_msg_va(struct quirks_context *ctx,
211 		 enum quirks_log_priorities priority,
212 		 const char *format,
213 		 va_list args)
214 {
215 	switch (priority) {
216 	/* We don't use this if we're logging through syslog */
217 	default:
218 	case QLOG_NOISE:
219 	case QLOG_PARSER_ERROR:
220 		if (ctx->log_type == QLOG_MOUSED_LOGGING)
221 			return;
222 		break;
223 	case QLOG_DEBUG: /* These map straight to syslog priorities */
224 	case QLOG_INFO:
225 	case QLOG_ERROR:
226 		break;
227 	}
228 
229 	ctx->log_handler(priority,
230 			 0,
231 			 format,
232 			 args);
233 }
234 
235 MOUSED_ATTRIBUTE_PRINTF(3, 4)
236 static inline void
quirk_log_msg(struct quirks_context * ctx,enum quirks_log_priorities priority,const char * format,...)237 quirk_log_msg(struct quirks_context *ctx,
238 	      enum quirks_log_priorities priority,
239 	      const char *format,
240 	      ...)
241 {
242 	va_list args;
243 
244 	va_start(args, format);
245 	quirk_log_msg_va(ctx, priority, format, args);
246 	va_end(args);
247 
248 }
249 
250 const char *
quirk_get_name(enum quirk q)251 quirk_get_name(enum quirk q)
252 {
253 	switch(q) {
254 	case QUIRK_MODEL_ALPS_SERIAL_TOUCHPAD:		return "ModelALPSSerialTouchpad";
255 	case QUIRK_MODEL_APPLE_TOUCHPAD:		return "ModelAppleTouchpad";
256 	case QUIRK_MODEL_APPLE_TOUCHPAD_ONEBUTTON:	return "ModelAppleTouchpadOneButton";
257 	case QUIRK_MODEL_BOUNCING_KEYS:			return "ModelBouncingKeys";
258 	case QUIRK_MODEL_CHROMEBOOK:			return "ModelChromebook";
259 	case QUIRK_MODEL_CLEVO_W740SU:			return "ModelClevoW740SU";
260 	case QUIRK_MODEL_DELL_CANVAS_TOTEM:		return "ModelDellCanvasTotem";
261 	case QUIRK_MODEL_HP_PAVILION_DM4_TOUCHPAD:	return "ModelHPPavilionDM4Touchpad";
262 	case QUIRK_MODEL_HP_ZBOOK_STUDIO_G3:		return "ModelHPZBookStudioG3";
263 	case QUIRK_MODEL_INVERT_HORIZONTAL_SCROLLING:	return "ModelInvertHorizontalScrolling";
264 	case QUIRK_MODEL_LENOVO_SCROLLPOINT:		return "ModelLenovoScrollPoint";
265 	case QUIRK_MODEL_LENOVO_T450_TOUCHPAD:		return "ModelLenovoT450Touchpad";
266 	case QUIRK_MODEL_LENOVO_X1GEN6_TOUCHPAD:	return "ModelLenovoX1Gen6Touchpad";
267 	case QUIRK_MODEL_LENOVO_X230:			return "ModelLenovoX230";
268 	case QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD:	return "ModelSynapticsSerialTouchpad";
269 	case QUIRK_MODEL_SYSTEM76_BONOBO:		return "ModelSystem76Bonobo";
270 	case QUIRK_MODEL_SYSTEM76_GALAGO:		return "ModelSystem76Galago";
271 	case QUIRK_MODEL_SYSTEM76_KUDU:			return "ModelSystem76Kudu";
272 	case QUIRK_MODEL_TABLET_MODE_NO_SUSPEND:	return "ModelTabletModeNoSuspend";
273 	case QUIRK_MODEL_TABLET_MODE_SWITCH_UNRELIABLE:	return "ModelTabletModeSwitchUnreliable";
274 	case QUIRK_MODEL_TOUCHPAD_VISIBLE_MARKER:	return "ModelTouchpadVisibleMarker";
275 	case QUIRK_MODEL_TOUCHPAD_PHANTOM_CLICKS:	return "ModelTouchpadPhantomClicks";
276 	case QUIRK_MODEL_TRACKBALL:			return "ModelTrackball";
277 	case QUIRK_MODEL_WACOM_TOUCHPAD:		return "ModelWacomTouchpad";
278 	case QUIRK_MODEL_PRESSURE_PAD:			return "ModelPressurePad";
279 
280 	case QUIRK_ATTR_SIZE_HINT:			return "AttrSizeHint";
281 	case QUIRK_ATTR_TOUCH_SIZE_RANGE:		return "AttrTouchSizeRange";
282 	case QUIRK_ATTR_PALM_SIZE_THRESHOLD:		return "AttrPalmSizeThreshold";
283 	case QUIRK_ATTR_LID_SWITCH_RELIABILITY:		return "AttrLidSwitchReliability";
284 	case QUIRK_ATTR_KEYBOARD_INTEGRATION:		return "AttrKeyboardIntegration";
285 	case QUIRK_ATTR_TRACKPOINT_INTEGRATION:		return "AttrPointingStickIntegration";
286 	case QUIRK_ATTR_TPKBCOMBO_LAYOUT:		return "AttrTPKComboLayout";
287 	case QUIRK_ATTR_PRESSURE_RANGE:			return "AttrPressureRange";
288 	case QUIRK_ATTR_PALM_PRESSURE_THRESHOLD:	return "AttrPalmPressureThreshold";
289 	case QUIRK_ATTR_RESOLUTION_HINT:		return "AttrResolutionHint";
290 	case QUIRK_ATTR_TRACKPOINT_MULTIPLIER:		return "AttrTrackpointMultiplier";
291 	case QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD:	return "AttrThumbPressureThreshold";
292 	case QUIRK_ATTR_USE_VELOCITY_AVERAGING:		return "AttrUseVelocityAveraging";
293 	case QUIRK_ATTR_TABLET_SMOOTHING:               return "AttrTabletSmoothing";
294 	case QUIRK_ATTR_THUMB_SIZE_THRESHOLD:		return "AttrThumbSizeThreshold";
295 	case QUIRK_ATTR_MSC_TIMESTAMP:			return "AttrMscTimestamp";
296 	case QUIRK_ATTR_EVENT_CODE:			return "AttrEventCode";
297 	case QUIRK_ATTR_INPUT_PROP:			return "AttrInputProp";
298 
299 	case MOUSED_GRAB_DEVICE:			return "MousedGrabDevice";
300 	case MOUSED_IGNORE_DEVICE:			return "MousedIgnoreDevice";
301 
302 	case MOUSED_CLICK_THRESHOLD:			return "MousedClickThreshold";
303 	case MOUSED_DRIFT_TERMINATE:			return "MousedDriftTerminate";
304 	case MOUSED_DRIFT_DISTANCE:			return "MousedDriftDistance";
305 	case MOUSED_DRIFT_TIME:				return "MousedDriftTime";
306 	case MOUSED_DRIFT_AFTER:			return "MousedDriftAfter";
307 	case MOUSED_EMULATE_THIRD_BUTTON:		return "MousedEmulateThirdButton";
308 	case MOUSED_EMULATE_THIRD_BUTTON_TIMEOUT:	return "MousedEmulateThirdButtonTimeout";
309 	case MOUSED_EXPONENTIAL_ACCEL:			return "MousedExponentialAccel";
310 	case MOUSED_EXPONENTIAL_OFFSET:			return "MousedExponentialOffset";
311 	case MOUSED_LINEAR_ACCEL_X:			return "MousedLinearAccelX";
312 	case MOUSED_LINEAR_ACCEL_Y:			return "MousedLinearAccelY";
313 	case MOUSED_LINEAR_ACCEL_Z:			return "MousedLinearAccelZ";
314 	case MOUSED_MAP_Z_AXIS:				return "MousedMapZAxis";
315 	case MOUSED_VIRTUAL_SCROLL_ENABLE:		return "MousedVirtualScrollEnable";
316 	case MOUSED_HOR_VIRTUAL_SCROLL_ENABLE:		return "MousedHorVirtualScrollEnable";
317 	case MOUSED_VIRTUAL_SCROLL_SPEED:		return "MousedVirtualScrollSpeed";
318 	case MOUSED_VIRTUAL_SCROLL_THRESHOLD:		return "MousedVirtualScrollThreshold";
319 	case MOUSED_WMODE:				return "MousedWMode";
320 
321 	case MOUSED_TWO_FINGER_SCROLL:			return "MousedTwoFingerScroll";
322 	case MOUSED_NATURAL_SCROLL:			return "MousedNaturalScroll";
323 	case MOUSED_THREE_FINGER_DRAG:			return "MousedThreeFingerDrag";
324 	case MOUSED_SOFTBUTTON2_X:			return "MousedSoftButton2X";
325 	case MOUSED_SOFTBUTTON3_X:			return "MousedSoftButton3X";
326 	case MOUSED_SOFTBUTTONS_Y:			return "MousedSoftButtonsY";
327 	case MOUSED_TAP_TIMEOUT:			return "MousedTapTimeout";
328 	case MOUSED_TAP_PRESSURE_THRESHOLD:		return "MousedTapPressureThreshold";
329 	case MOUSED_TAP_MAX_DELTA:			return "MousedTapMaxDelta";
330 	case MOUSED_TAPHOLD_TIMEOUT:			return "MousedTapholdTimeout";
331 	case MOUSED_VSCROLL_MIN_DELTA:			return "MousedVScrollMinDelta";
332 	case MOUSED_VSCROLL_HOR_AREA:			return "MousedVScrollHorArea";
333 	case MOUSED_VSCROLL_VER_AREA:			return "MousedVScrollVerArea";
334 
335 
336 	default:
337 		abort();
338 	}
339 }
340 
341 static inline const char *
matchflagname(enum match_flags f)342 matchflagname(enum match_flags f)
343 {
344 	switch(f) {
345 	case M_NAME:		return "MatchName";		break;
346 	case M_BUS:		return "MatchBus";		break;
347 	case M_VID:		return "MatchVendor";		break;
348 	case M_PID:		return "MatchProduct";		break;
349 	case M_VERSION:		return "MatchVersion";		break;
350 	case M_DMI:		return "MatchDMIModalias";	break;
351 	case M_UDEV_TYPE:	return "MatchDevType";		break;
352 	case M_DT:		return "MatchDeviceTree";	break;
353 	case M_UNIQ:		return "MatchUniq";		break;
354 	default:
355 		abort();
356 	}
357 }
358 
359 static inline struct property *
property_new(void)360 property_new(void)
361 {
362 	struct property *p;
363 
364 	p = zalloc(sizeof *p);
365 	p->refcount = 1;
366 	list_init(&p->link);
367 
368 	return p;
369 }
370 
371 static inline struct property *
property_ref(struct property * p)372 property_ref(struct property *p)
373 {
374 	assert(p->refcount > 0);
375 	p->refcount++;
376 	return p;
377 }
378 
379 static inline struct property *
property_unref(struct property * p)380 property_unref(struct property *p)
381 {
382 	/* Note: we don't cleanup here, that is a separate call so we
383 	   can abort if we haven't cleaned up correctly.  */
384 	assert(p->refcount > 0);
385 	p->refcount--;
386 
387 	return NULL;
388 }
389 
390 /* Separate call so we can verify that the caller unrefs the property
391  * before shutting down the subsystem.
392  */
393 static inline void
property_cleanup(struct property * p)394 property_cleanup(struct property *p)
395 {
396 	/* If we get here, the quirks must've been removed already */
397 	property_unref(p);
398 	assert(p->refcount == 0);
399 
400 	list_remove(&p->link);
401 	if (p->type == PT_STRING)
402 		free(p->value.s);
403 	free(p);
404 }
405 
406 /**
407  * Return the system DMI info in modalias format.
408  */
409 static inline char *
init_dmi(void)410 init_dmi(void)
411 {
412 #define LEN (KENV_MVALLEN + 1)
413 	char *modalias;
414 	char bios_vendor[LEN], bios_version[LEN], bios_date[LEN];
415 	char sys_vendor[LEN], product_name[LEN], product_version[LEN];
416 	char board_vendor[LEN], board_name[LEN], board_version[LEN];
417 	char chassis_vendor[LEN], chassis_type[LEN], chassis_version[LEN];
418 	int chassis_type_num = 0x2;
419 
420 	kenv(KENV_GET, "smbios.bios.vendor", bios_vendor, LEN);
421 	kenv(KENV_GET, "smbios.bios.version", bios_version, LEN);
422 	kenv(KENV_GET, "smbios.bios.reldate", bios_date, LEN);
423 	kenv(KENV_GET, "smbios.system.maker", sys_vendor, LEN);
424 	kenv(KENV_GET, "smbios.system.product", product_name, LEN);
425 	kenv(KENV_GET, "smbios.system.version", product_version, LEN);
426 	kenv(KENV_GET, "smbios.planar.maker", board_vendor, LEN);
427 	kenv(KENV_GET, "smbios.planar.product", board_name, LEN);
428 	kenv(KENV_GET, "smbios.planar.version", board_version, LEN);
429 	kenv(KENV_GET, "smbios.chassis.vendor", chassis_vendor, LEN);
430 	kenv(KENV_GET, "smbios.chassis.type", chassis_type, LEN);
431 	kenv(KENV_GET, "smbios.chassis.version", chassis_version, LEN);
432 #undef LEN
433 
434 	if (strcmp(chassis_type, "Desktop") == 0)
435 		chassis_type_num = 0x3;
436 	else if (strcmp(chassis_type, "Portable") == 0)
437 		chassis_type_num = 0x8;
438 	else if (strcmp(chassis_type, "Laptop") == 0)
439 		chassis_type_num = 0x9;
440 	else if (strcmp(chassis_type, "Notebook") == 0)
441 		chassis_type_num = 0xA;
442 	else if (strcmp(chassis_type, "Tablet") == 0)
443 		chassis_type_num = 0x1E;
444 	else if (strcmp(chassis_type, "Convertible") == 0)
445 		chassis_type_num = 0x1F;
446 	else if (strcmp(chassis_type, "Detachable") == 0)
447 		chassis_type_num = 0x20;
448 
449 	xasprintf(&modalias,
450 		"dmi:bvn%s:bvr%s:bd%s:svn%s:pn%s:pvr%s:rvn%s:rn%s:rvr%s:cvn%s:ct%d:cvr%s:",
451 		bios_vendor, bios_version, bios_date, sys_vendor, product_name,
452 		product_version, board_vendor, board_name, board_version, chassis_vendor,
453 		chassis_type_num, chassis_version);
454 
455 	return modalias;
456 }
457 
458 /**
459  * Return the dt compatible string
460  */
461 static inline char *
init_dt(void)462 init_dt(void)
463 {
464 	char compatible[1024];
465 	char *copy = NULL;
466 	const char *syspath = "/sys/firmware/devicetree/base/compatible";
467 	FILE *fp;
468 
469 	if (getenv("LIBINPUT_RUNNING_TEST_SUITE"))
470 		return safe_strdup("");
471 
472 	fp = fopen(syspath, "r");
473 	if (!fp)
474 		return NULL;
475 
476 	/* devicetree/base/compatible has multiple null-terminated entries
477 	   but we only care about the first one here, so strdup is enough */
478 	if (fgets(compatible, sizeof(compatible), fp)) {
479 		copy = safe_strdup(compatible);
480 	}
481 
482 	fclose(fp);
483 
484 	return copy;
485 }
486 
487 static inline struct section *
section_new(const char * path,const char * name)488 section_new(const char *path, const char *name)
489 {
490 	struct section *s = zalloc(sizeof(*s));
491 
492 	char *path_dup = safe_strdup(path);
493 	xasprintf(&s->name, "%s (%s)", name, basename(path_dup));
494 	free(path_dup);
495 	list_init(&s->link);
496 	list_init(&s->properties);
497 
498 	return s;
499 }
500 
501 static inline void
section_destroy(struct section * s)502 section_destroy(struct section *s)
503 {
504 	struct property *p;
505 
506 	free(s->name);
507 	free(s->match.name);
508 	free(s->match.uniq);
509 	free(s->match.dmi);
510 	free(s->match.dt);
511 
512 	list_for_each_safe(p, &s->properties, link)
513 		property_cleanup(p);
514 
515 	assert(list_empty(&s->properties));
516 
517 	list_remove(&s->link);
518 	free(s);
519 }
520 
521 static inline bool
parse_hex(const char * value,unsigned int * parsed)522 parse_hex(const char *value, unsigned int *parsed)
523 {
524 	return strstartswith(value, "0x") &&
525 	       safe_atou_base(value, parsed, 16) &&
526 	       strspn(value, "0123456789xABCDEF") == strlen(value) &&
527 	       *parsed <= 0xFFFF;
528 }
529 
530 static int
strv_parse_hex(const char * str,size_t index,void * data)531 strv_parse_hex(const char *str, size_t index, void *data)
532 {
533 	unsigned int *product = data;
534 
535 	return !parse_hex(str, &product[index]); /* 0 for success */
536 }
537 
538 /**
539  * Parse a MatchFooBar=banana line.
540  *
541  * @param section The section struct to be filled in
542  * @param key The MatchFooBar part of the line
543  * @param value The banana part of the line.
544  *
545  * @return true on success, false otherwise.
546  */
547 static bool
parse_match(struct quirks_context * ctx,struct section * s,const char * key,const char * value)548 parse_match(struct quirks_context *ctx,
549 	    struct section *s,
550 	    const char *key,
551 	    const char *value)
552 {
553 	int rc = false;
554 
555 #define check_set_bit(s_, bit_) { \
556 		if ((s_)->match.bits & (bit_)) goto out; \
557 		(s_)->match.bits |= (bit_); \
558 	}
559 
560 	assert(strlen(value) >= 1);
561 
562 	if (streq(key, "MatchName")) {
563 		check_set_bit(s, M_NAME);
564 		s->match.name = safe_strdup(value);
565 	} else if (streq(key, "MatchUniq")) {
566 		check_set_bit(s, M_UNIQ);
567 		s->match.uniq = safe_strdup(value);
568 	} else if (streq(key, "MatchBus")) {
569 		check_set_bit(s, M_BUS);
570 		if (streq(value, "usb"))
571 			s->match.bus = BT_USB;
572 		else if (streq(value, "bluetooth"))
573 			s->match.bus = BT_BLUETOOTH;
574 		else if (streq(value, "ps2"))
575 			s->match.bus = BT_PS2;
576 		else if (streq(value, "rmi"))
577 			s->match.bus = BT_RMI;
578 		else if (streq(value, "i2c"))
579 			s->match.bus = BT_I2C;
580 		else if (streq(value, "spi"))
581 			s->match.bus = BT_SPI;
582 		else
583 			goto out;
584 	} else if (streq(key, "MatchVendor")) {
585 		unsigned int vendor;
586 
587 		check_set_bit(s, M_VID);
588 		if (!parse_hex(value, &vendor))
589 			goto out;
590 
591 		s->match.vendor = vendor;
592 	} else if (streq(key, "MatchProduct")) {
593 		unsigned int product[ARRAY_LENGTH(s->match.product)] = {0};
594 		const size_t max = ARRAY_LENGTH(s->match.product) - 1;
595 
596 		size_t nelems = 0;
597 		char **strs = strv_from_string(value, ";", &nelems);
598 		int rc = strv_for_each_n((const char**)strs, max, strv_parse_hex, product);
599 		strv_free(strs);
600 		if (rc != 0)
601 			goto out;
602 
603 		check_set_bit(s, M_PID);
604 		memcpy(s->match.product, product, sizeof(product));
605 	} else if (streq(key, "MatchVersion")) {
606 		unsigned int version;
607 
608 		check_set_bit(s, M_VERSION);
609 		if (!parse_hex(value, &version))
610 			goto out;
611 
612 		s->match.version = version;
613 	} else if (streq(key, "MatchDMIModalias")) {
614 		check_set_bit(s, M_DMI);
615 		if (!strstartswith(value, "dmi:")) {
616 			qlog_parser(ctx,
617 				    "%s: MatchDMIModalias must start with 'dmi:'\n",
618 				    s->name);
619 			goto out;
620 		}
621 		s->match.dmi = safe_strdup(value);
622 	} else if (streq(key, "MatchUdevType") || streq(key, "MatchDevType")) {
623 		check_set_bit(s, M_UDEV_TYPE);
624 		if (streq(value, "touchpad"))
625 			s->match.udev_type = UDEV_TOUCHPAD;
626 		else if (streq(value, "mouse"))
627 			s->match.udev_type = UDEV_MOUSE;
628 		else if (streq(value, "pointingstick"))
629 			s->match.udev_type = UDEV_POINTINGSTICK;
630 		else if (streq(value, "keyboard"))
631 			s->match.udev_type = UDEV_KEYBOARD;
632 		else if (streq(value, "joystick"))
633 			s->match.udev_type = UDEV_JOYSTICK;
634 		else if (streq(value, "tablet"))
635 			s->match.udev_type = UDEV_TABLET;
636 		else if (streq(value, "tablet-pad"))
637 			s->match.udev_type = UDEV_TABLET_PAD;
638 		else
639 			goto out;
640 	} else if (streq(key, "MatchDeviceTree")) {
641 		check_set_bit(s, M_DT);
642 		s->match.dt = safe_strdup(value);
643 	} else {
644 		qlog_error(ctx, "Unknown match key '%s'\n", key);
645 		goto out;
646 	}
647 
648 #undef check_set_bit
649 	s->has_match = true;
650 	rc = true;
651 out:
652 	return rc;
653 }
654 
655 /**
656  * Parse a ModelFooBar=1 line.
657  *
658  * @param section The section struct to be filled in
659  * @param key The ModelFooBar part of the line
660  * @param value The value after the =, must be 1 or 0.
661  *
662  * @return true on success, false otherwise.
663  */
664 static bool
parse_model(struct quirks_context * ctx,struct section * s,const char * key,const char * value)665 parse_model(struct quirks_context *ctx,
666 	    struct section *s,
667 	    const char *key,
668 	    const char *value)
669 {
670 	bool b;
671 	enum quirk q = QUIRK_MODEL_ALPS_SERIAL_TOUCHPAD;
672 
673 	assert(strstartswith(key, "Model"));
674 
675 	if (!parse_boolean_property(value, &b))
676 		return false;
677 
678 	do {
679 		if (streq(key, quirk_get_name(q))) {
680 			struct property *p = property_new();
681 			p->id = q,
682 			p->type = PT_BOOL;
683 			p->value.b = b;
684 			list_append(&s->properties, &p->link);
685 			s->has_property = true;
686 			return true;
687 		}
688 	} while (++q < _QUIRK_LAST_MODEL_QUIRK_);
689 
690 	qlog_error(ctx, "Unknown key %s in %s\n", key, s->name);
691 
692 	return false;
693 }
694 
695 /**
696  * Parse a AttrFooBar=banana line.
697  *
698  * @param section The section struct to be filled in
699  * @param key The AttrFooBar part of the line
700  * @param value The banana part of the line.
701  *
702  * Value parsing depends on the attribute type.
703  *
704  * @return true on success, false otherwise.
705  */
706 static inline bool
parse_attr(struct quirks_context * ctx,struct section * s,const char * key,const char * value)707 parse_attr(struct quirks_context *ctx,
708 	   struct section *s,
709 	   const char *key,
710 	   const char *value)
711 {
712 	struct property *p = property_new();
713 	bool rc = false;
714 	struct quirk_dimensions dim;
715 	struct quirk_range range;
716 	unsigned int v;
717 	bool b;
718 	double d;
719 
720 	if (streq(key, quirk_get_name(QUIRK_ATTR_SIZE_HINT))) {
721 		p->id = QUIRK_ATTR_SIZE_HINT;
722 		if (!parse_dimension_property(value, &dim.x, &dim.y))
723 			goto out;
724 		p->type = PT_DIMENSION;
725 		p->value.dim = dim;
726 		rc = true;
727 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_TOUCH_SIZE_RANGE))) {
728 		p->id = QUIRK_ATTR_TOUCH_SIZE_RANGE;
729 		if (!parse_range_property(value, &range.upper, &range.lower))
730 			goto out;
731 		p->type = PT_RANGE;
732 		p->value.range = range;
733 		rc = true;
734 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_PALM_SIZE_THRESHOLD))) {
735 		p->id = QUIRK_ATTR_PALM_SIZE_THRESHOLD;
736 		if (!safe_atou(value, &v))
737 			goto out;
738 		p->type = PT_UINT;
739 		p->value.u = v;
740 		rc = true;
741 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_LID_SWITCH_RELIABILITY))) {
742 		p->id = QUIRK_ATTR_LID_SWITCH_RELIABILITY;
743 		if (!streq(value, "reliable") &&
744 		    !streq(value, "write_open") &&
745 		    !streq(value, "unreliable"))
746 			goto out;
747 		p->type = PT_STRING;
748 		p->value.s = safe_strdup(value);
749 		rc = true;
750 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_KEYBOARD_INTEGRATION))) {
751 		p->id = QUIRK_ATTR_KEYBOARD_INTEGRATION;
752 		if (!streq(value, "internal") && !streq(value, "external"))
753 			goto out;
754 		p->type = PT_STRING;
755 		p->value.s = safe_strdup(value);
756 		rc = true;
757 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_TRACKPOINT_INTEGRATION))) {
758 		p->id = QUIRK_ATTR_TRACKPOINT_INTEGRATION;
759 		if (!streq(value, "internal") && !streq(value, "external"))
760 			goto out;
761 		p->type = PT_STRING;
762 		p->value.s = safe_strdup(value);
763 		rc = true;
764 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_TPKBCOMBO_LAYOUT))) {
765 		p->id = QUIRK_ATTR_TPKBCOMBO_LAYOUT;
766 		if (!streq(value, "below"))
767 			goto out;
768 		p->type = PT_STRING;
769 		p->value.s = safe_strdup(value);
770 		rc = true;
771 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_PRESSURE_RANGE))) {
772 		p->id = QUIRK_ATTR_PRESSURE_RANGE;
773 		if (!parse_range_property(value, &range.upper, &range.lower))
774 			goto out;
775 		p->type = PT_RANGE;
776 		p->value.range = range;
777 		rc = true;
778 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_PALM_PRESSURE_THRESHOLD))) {
779 		p->id = QUIRK_ATTR_PALM_PRESSURE_THRESHOLD;
780 		if (!safe_atou(value, &v))
781 			goto out;
782 		p->type = PT_UINT;
783 		p->value.u = v;
784 		rc = true;
785 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_RESOLUTION_HINT))) {
786 		p->id = QUIRK_ATTR_RESOLUTION_HINT;
787 		if (!parse_dimension_property(value, &dim.x, &dim.y))
788 			goto out;
789 		p->type = PT_DIMENSION;
790 		p->value.dim = dim;
791 		rc = true;
792 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_TRACKPOINT_MULTIPLIER))) {
793 		p->id = QUIRK_ATTR_TRACKPOINT_MULTIPLIER;
794 		if (!safe_atod(value, &d))
795 			goto out;
796 		p->type = PT_DOUBLE;
797 		p->value.d = d;
798 		rc = true;
799 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_USE_VELOCITY_AVERAGING))) {
800 		p->id = QUIRK_ATTR_USE_VELOCITY_AVERAGING;
801 		if (!parse_boolean_property(value, &b))
802 			goto out;
803 		p->type = PT_BOOL;
804 		p->value.b = b;
805 		rc = true;
806 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_TABLET_SMOOTHING))) {
807 		p->id = QUIRK_ATTR_TABLET_SMOOTHING;
808 		if (!parse_boolean_property(value, &b))
809 			goto out;
810 		p->type = PT_BOOL;
811 		p->value.b = b;
812 		rc = true;
813 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD))) {
814 		p->id = QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD;
815 		if (!safe_atou(value, &v))
816 			goto out;
817 		p->type = PT_UINT;
818 		p->value.u = v;
819 		rc = true;
820 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_THUMB_SIZE_THRESHOLD))) {
821 		p->id = QUIRK_ATTR_THUMB_SIZE_THRESHOLD;
822 		if (!safe_atou(value, &v))
823 			goto out;
824 		p->type = PT_UINT;
825 		p->value.u = v;
826 		rc = true;
827 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_MSC_TIMESTAMP))) {
828 		p->id = QUIRK_ATTR_MSC_TIMESTAMP;
829 		if (!streq(value, "watch"))
830 			goto out;
831 		p->type = PT_STRING;
832 		p->value.s = safe_strdup(value);
833 		rc = true;
834 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_EVENT_CODE))) {
835 		struct input_event events[32];
836 		size_t nevents = ARRAY_LENGTH(events);
837 
838 		p->id = QUIRK_ATTR_EVENT_CODE;
839 
840 		if (!parse_evcode_property(value, events, &nevents) ||
841 		    nevents == 0)
842 			goto out;
843 
844 		for (size_t i = 0; i < nevents; i++) {
845 			p->value.tuples.tuples[i].first = events[i].type;
846 			p->value.tuples.tuples[i].second = events[i].code;
847 			p->value.tuples.tuples[i].third = events[i].value;
848 		}
849 		p->value.tuples.ntuples = nevents;
850 		p->type = PT_TUPLES;
851 
852 		rc = true;
853 	} else if (streq(key, quirk_get_name(QUIRK_ATTR_INPUT_PROP))) {
854 		struct input_prop props[INPUT_PROP_CNT];
855 		size_t nprops = ARRAY_LENGTH(props);
856 
857 		p->id = QUIRK_ATTR_INPUT_PROP;
858 
859 		if (!parse_input_prop_property(value, props, &nprops) ||
860 		    nprops == 0)
861 			goto out;
862 
863 		for (size_t i = 0; i < nprops; i++) {
864 			p->value.tuples.tuples[i].first = props[i].prop;
865 			p->value.tuples.tuples[i].second = props[i].enabled;
866 		}
867 
868 		rc = true;
869 	} else {
870 		qlog_error(ctx, "Unknown key %s in %s\n", key, s->name);
871 	}
872 out:
873 	if (rc) {
874 		list_append(&s->properties, &p->link);
875 		s->has_property = true;
876 	} else {
877 		property_cleanup(p);
878 	}
879 	return rc;
880 }
881 
882 /**
883  * Parse a MousedFooBar=banana line.
884  *
885  * @param section The section struct to be filled in
886  * @param key The MousedFooBar part of the line
887  * @param value The banana part of the line.
888  *
889  * Value parsing depends on the attribute type.
890  *
891  * @return true on success, false otherwise.
892  */
893 static inline bool
parse_moused(struct quirks_context * ctx,struct section * s,const char * key,const char * value)894 parse_moused(struct quirks_context *ctx,
895 	     struct section *s,
896 	     const char *key,
897 	     const char *value)
898 {
899 	struct property *p = property_new();
900 	bool rc = false;
901 	struct quirk_dimensions dim;
902 	struct quirk_range range;
903 	unsigned int v;
904 	int i;
905 	bool b;
906 	double d;
907 
908 	if (streq(key, quirk_get_name(MOUSED_GRAB_DEVICE))) {
909 		p->id = MOUSED_GRAB_DEVICE;
910 		if (!parse_boolean_property(value, &b))
911 			goto out;
912 		p->type = PT_BOOL;
913 		p->value.b = b;
914 		rc = true;
915 	} else if (streq(key, quirk_get_name(MOUSED_IGNORE_DEVICE))) {
916 		p->id = MOUSED_IGNORE_DEVICE;
917 		if (!parse_boolean_property(value, &b))
918 			goto out;
919 		p->type = PT_BOOL;
920 		p->value.b = b;
921 		rc = true;
922 	} else if (streq(key, quirk_get_name(MOUSED_CLICK_THRESHOLD))) {
923 		p->id = MOUSED_CLICK_THRESHOLD;
924 		if (!safe_atou(value, &v))
925 			goto out;
926 		p->type = PT_UINT;
927 		p->value.u = v;
928 		rc = true;
929 	} else if (streq(key, quirk_get_name(MOUSED_DRIFT_TERMINATE))) {
930 		p->id = MOUSED_DRIFT_TERMINATE;
931 		if (!parse_boolean_property(value, &b))
932 			goto out;
933 		p->type = PT_BOOL;
934 		p->value.b = b;
935 		rc = true;
936 	} else if (streq(key, quirk_get_name(MOUSED_DRIFT_DISTANCE))) {
937 		p->id = MOUSED_DRIFT_DISTANCE;
938 		if (!safe_atou(value, &v))
939 			goto out;
940 		p->type = PT_UINT;
941 		p->value.u = v;
942 		rc = true;
943 	} else if (streq(key, quirk_get_name(MOUSED_DRIFT_TIME))) {
944 		p->id = MOUSED_DRIFT_TIME;
945 		if (!safe_atou(value, &v))
946 			goto out;
947 		p->type = PT_UINT;
948 		p->value.u = v;
949 		rc = true;
950 	} else if (streq(key, quirk_get_name(MOUSED_DRIFT_AFTER))) {
951 		p->id = MOUSED_DRIFT_AFTER;
952 		if (!safe_atou(value, &v))
953 			goto out;
954 		p->type = PT_UINT;
955 		p->value.u = v;
956 		rc = true;
957 	} else if (streq(key, quirk_get_name(MOUSED_EMULATE_THIRD_BUTTON))) {
958 		p->id = MOUSED_EMULATE_THIRD_BUTTON;
959 		if (!parse_boolean_property(value, &b))
960 			goto out;
961 		p->type = PT_BOOL;
962 		p->value.b = b;
963 		rc = true;
964 	} else if (streq(key, quirk_get_name(MOUSED_EMULATE_THIRD_BUTTON_TIMEOUT))) {
965 		p->id = MOUSED_EMULATE_THIRD_BUTTON_TIMEOUT;
966 		if (!safe_atou(value, &v))
967 			goto out;
968 		p->type = PT_UINT;
969 		p->value.u = v;
970 		rc = true;
971 	} else if (streq(key, quirk_get_name(MOUSED_EXPONENTIAL_ACCEL))) {
972 		p->id = MOUSED_EXPONENTIAL_ACCEL;
973 		if (!safe_atod(value, &d))
974 			goto out;
975 		p->type = PT_DOUBLE;
976 		p->value.d = d;
977 		rc = true;
978 	} else if (streq(key, quirk_get_name(MOUSED_EXPONENTIAL_OFFSET))) {
979 		p->id = MOUSED_EXPONENTIAL_OFFSET;
980 		if (!safe_atod(value, &d))
981 			goto out;
982 		p->type = PT_DOUBLE;
983 		p->value.d = d;
984 		rc = true;
985 	} else if (streq(key, quirk_get_name(MOUSED_LINEAR_ACCEL_X))) {
986 		p->id = MOUSED_LINEAR_ACCEL_X;
987 		if (!safe_atod(value, &d))
988 			goto out;
989 		p->type = PT_DOUBLE;
990 		p->value.d = d;
991 		rc = true;
992 	} else if (streq(key, quirk_get_name(MOUSED_LINEAR_ACCEL_Y))) {
993 		p->id = MOUSED_LINEAR_ACCEL_Y;
994 		if (!safe_atod(value, &d))
995 			goto out;
996 		p->type = PT_DOUBLE;
997 		p->value.d = d;
998 		rc = true;
999 	} else if (streq(key, quirk_get_name(MOUSED_LINEAR_ACCEL_Z))) {
1000 		p->id = MOUSED_LINEAR_ACCEL_Z;
1001 		if (!safe_atod(value, &d))
1002 			goto out;
1003 		p->type = PT_DOUBLE;
1004 		p->value.d = d;
1005 		rc = true;
1006 	} else if (streq(key, quirk_get_name(MOUSED_MAP_Z_AXIS))) {
1007 	} else if (streq(key, quirk_get_name(MOUSED_VIRTUAL_SCROLL_ENABLE))) {
1008 		p->id = MOUSED_VIRTUAL_SCROLL_ENABLE;
1009 		if (!parse_boolean_property(value, &b))
1010 			goto out;
1011 		p->type = PT_BOOL;
1012 		p->value.b = b;
1013 		rc = true;
1014 	} else if (streq(key, quirk_get_name(MOUSED_HOR_VIRTUAL_SCROLL_ENABLE))) {
1015 		p->id = MOUSED_HOR_VIRTUAL_SCROLL_ENABLE;
1016 		if (!parse_boolean_property(value, &b))
1017 			goto out;
1018 		p->type = PT_BOOL;
1019 		p->value.b = b;
1020 		rc = true;
1021 	} else if (streq(key, quirk_get_name(MOUSED_VIRTUAL_SCROLL_SPEED))) {
1022 		p->id = MOUSED_VIRTUAL_SCROLL_SPEED;
1023 		if (!safe_atou(value, &v))
1024 			goto out;
1025 		p->type = PT_UINT;
1026 		p->value.u = v;
1027 		rc = true;
1028 	} else if (streq(key, quirk_get_name(MOUSED_VIRTUAL_SCROLL_THRESHOLD))) {
1029 		p->id = MOUSED_VIRTUAL_SCROLL_THRESHOLD;
1030 		if (!safe_atou(value, &v))
1031 			goto out;
1032 		p->type = PT_UINT;
1033 		p->value.u = v;
1034 		rc = true;
1035 	} else if (streq(key, quirk_get_name(MOUSED_WMODE))) {
1036 		p->id = MOUSED_WMODE;
1037 		if (!safe_atou(value, &v))
1038 			goto out;
1039 		p->type = PT_UINT;
1040 		p->value.u = v;
1041 		rc = true;
1042 	} else if (streq(key, quirk_get_name(MOUSED_TWO_FINGER_SCROLL))) {
1043 		p->id = MOUSED_TWO_FINGER_SCROLL;
1044 		if (!parse_boolean_property(value, &b))
1045 			goto out;
1046 		p->type = PT_BOOL;
1047 		p->value.b = b;
1048 		rc = true;
1049 	} else if (streq(key, quirk_get_name(MOUSED_NATURAL_SCROLL))) {
1050 		p->id = MOUSED_NATURAL_SCROLL;
1051 		if (!parse_boolean_property(value, &b))
1052 			goto out;
1053 		p->type = PT_BOOL;
1054 		p->value.b = b;
1055 		rc = true;
1056 	} else if (streq(key, quirk_get_name(MOUSED_THREE_FINGER_DRAG))) {
1057 		p->id = MOUSED_THREE_FINGER_DRAG;
1058 		if (!parse_boolean_property(value, &b))
1059 			goto out;
1060 		p->type = PT_BOOL;
1061 		p->value.b = b;
1062 		rc = true;
1063 	} else if (streq(key, quirk_get_name(MOUSED_SOFTBUTTON2_X))) {
1064 		p->id = MOUSED_SOFTBUTTON2_X;
1065 		if (!safe_atou(value, &v))
1066 			goto out;
1067 		p->type = PT_UINT;
1068 		p->value.u = v;
1069 		rc = true;
1070 	} else if (streq(key, quirk_get_name(MOUSED_SOFTBUTTON3_X))) {
1071 		p->id = MOUSED_SOFTBUTTON3_X;
1072 		if (!safe_atou(value, &v))
1073 			goto out;
1074 		p->type = PT_UINT;
1075 		p->value.u = v;
1076 		rc = true;
1077 	} else if (streq(key, quirk_get_name(MOUSED_SOFTBUTTONS_Y))) {
1078 		p->id = MOUSED_SOFTBUTTONS_Y;
1079 		if (!safe_atoi(value, &i))
1080 			goto out;
1081 		p->type = PT_INT;
1082 		p->value.i = i;
1083 		rc = true;
1084 	} else if (streq(key, quirk_get_name(MOUSED_TAP_TIMEOUT))) {
1085 		p->id = MOUSED_TAP_TIMEOUT;
1086 		if (!safe_atou(value, &v))
1087 			goto out;
1088 		p->type = PT_UINT;
1089 		p->value.u = v;
1090 		rc = true;
1091 	} else if (streq(key, quirk_get_name(MOUSED_TAP_PRESSURE_THRESHOLD))) {
1092 		p->id = MOUSED_TAP_PRESSURE_THRESHOLD;
1093 		if (!safe_atou(value, &v))
1094 			goto out;
1095 		p->type = PT_UINT;
1096 		p->value.u = v;
1097 		rc = true;
1098 	} else if (streq(key, quirk_get_name(MOUSED_TAP_MAX_DELTA))) {
1099 		p->id = MOUSED_TAP_MAX_DELTA;
1100 		if (!safe_atod(value, &d))
1101 			goto out;
1102 		p->type = PT_DOUBLE;
1103 		p->value.d = d;
1104 		rc = true;
1105 	} else if (streq(key, quirk_get_name(MOUSED_TAPHOLD_TIMEOUT))) {
1106 		p->id = MOUSED_TAPHOLD_TIMEOUT;
1107 		if (!safe_atou(value, &v))
1108 			goto out;
1109 		p->type = PT_UINT;
1110 		p->value.u = v;
1111 		rc = true;
1112 	} else if (streq(key, quirk_get_name(MOUSED_VSCROLL_MIN_DELTA))) {
1113 		p->id = MOUSED_VSCROLL_MIN_DELTA;
1114 		if (!safe_atod(value, &d))
1115 			goto out;
1116 		p->type = PT_DOUBLE;
1117 		p->value.d = d;
1118 		rc = true;
1119 	} else if (streq(key, quirk_get_name(MOUSED_VSCROLL_HOR_AREA))) {
1120 		p->id = MOUSED_VSCROLL_HOR_AREA;
1121 		if (!safe_atod(value, &d))
1122 			goto out;
1123 		p->type = PT_DOUBLE;
1124 		p->value.d = d;
1125 		rc = true;
1126 	} else if (streq(key, quirk_get_name(MOUSED_VSCROLL_VER_AREA))) {
1127 		p->id = MOUSED_VSCROLL_VER_AREA;
1128 		if (!safe_atod(value, &d))
1129 			goto out;
1130 		p->type = PT_DOUBLE;
1131 		p->value.d = d;
1132 		rc = true;
1133 	} else {
1134 		qlog_error(ctx, "Unknown key %s in %s\n", key, s->name);
1135 	}
1136 out:
1137 	if (rc) {
1138 		list_append(&s->properties, &p->link);
1139 		s->has_property = true;
1140 	} else {
1141 		property_cleanup(p);
1142 	}
1143 	return rc;
1144 }
1145 
1146 /**
1147  * Parse a single line, expected to be in the format Key=value. Anything
1148  * else will be rejected with a failure.
1149  *
1150  * Our data files can only have Match, Model and Attr, so let's check for
1151  * those too.
1152  */
1153 static bool
parse_value_line(struct quirks_context * ctx,struct section * s,const char * line)1154 parse_value_line(struct quirks_context *ctx, struct section *s, const char *line)
1155 {
1156 	bool rc = false;
1157 
1158 	size_t nelem;
1159 	char **strv = strv_from_string(line, "=", &nelem);
1160 	if (!strv || nelem != 2)
1161 		goto out;
1162 
1163 	const char *key = strv[0];
1164 	const char *value = strv[1];
1165 	if (strlen(key) == 0 || strlen(value) == 0)
1166 		goto out;
1167 
1168 	/* Whatever the value is, it's not supposed to be in quotes */
1169 	if (value[0] == '"' || value[0] == '\'')
1170 		goto out;
1171 
1172 	if (strstartswith(key, "Match"))
1173 		rc = parse_match(ctx, s, key, value);
1174 	else if (strstartswith(key, "Model"))
1175 		rc = parse_model(ctx, s, key, value);
1176 	else if (strstartswith(key, "Attr"))
1177 		rc = parse_attr(ctx, s, key, value);
1178 	else if (strstartswith(key, "Moused"))
1179 		rc = parse_moused(ctx, s, key, value);
1180 	else
1181 		qlog_error(ctx, "Unknown value prefix %s\n", line);
1182 out:
1183 	strv_free(strv);
1184 	return rc;
1185 }
1186 
1187 static inline bool
parse_file(struct quirks_context * ctx,const char * path)1188 parse_file(struct quirks_context *ctx, const char *path)
1189 {
1190 	enum state {
1191 		STATE_SECTION,
1192 		STATE_MATCH,
1193 		STATE_MATCH_OR_VALUE,
1194 		STATE_VALUE_OR_SECTION,
1195 		STATE_ANY,
1196 	};
1197 	FILE *fp;
1198 	char line[512];
1199 	bool rc = false;
1200 	enum state state = STATE_SECTION;
1201 	struct section *section = NULL;
1202 	int lineno = -1;
1203 
1204 	qlog_debug(ctx, "%s\n", path);
1205 
1206 	/* Not using open_restricted here, if we can't access
1207 	 * our own data files, our installation is screwed up.
1208 	 */
1209 	fp = fopen(path, "r");
1210 	if (!fp) {
1211 		/* If the file doesn't exist that's fine. Only way this can
1212 		 * happen is for the custom override file, all others are
1213 		 * provided by scandir so they do exist. Short of races we
1214 		 * don't care about. */
1215 		if (errno == ENOENT)
1216 			return true;
1217 
1218 		qlog_error(ctx, "%s: failed to open file\n", path);
1219 		goto out;
1220 	}
1221 
1222 	while (fgets(line, sizeof(line), fp)) {
1223 		char *comment;
1224 
1225 		lineno++;
1226 
1227 		comment = strstr(line, "#");
1228 		if (comment) {
1229 			/* comment points to # but we need to remove the
1230 			 * preceding whitespaces too */
1231 			comment--;
1232 			while (comment >= line) {
1233 				if (*comment != ' ' && *comment != '\t')
1234 					break;
1235 				comment--;
1236 			}
1237 			*(comment + 1) = '\0';
1238 		} else { /* strip the trailing newline */
1239 			comment = strstr(line, "\n");
1240 			if (comment)
1241 				*comment = '\0';
1242 		}
1243 		if (strlen(line) == 0)
1244 			continue;
1245 
1246 		/* We don't use quotes for strings, so we really don't want
1247 		 * erroneous trailing whitespaces */
1248 		switch (line[strlen(line) - 1]) {
1249 		case ' ':
1250 		case '\t':
1251 			qlog_parser(ctx,
1252 				    "%s:%d: Trailing whitespace '%s'\n",
1253 				    path, lineno, line);
1254 			goto out;
1255 		}
1256 
1257 		switch (line[0]) {
1258 		case '\0':
1259 		case '\n':
1260 		case '#':
1261 			break;
1262 		/* white space not allowed */
1263 		case ' ':
1264 		case '\t':
1265 			qlog_parser(ctx, "%s:%d: Preceding whitespace '%s'\n",
1266 					 path, lineno, line);
1267 			goto out;
1268 		/* section title */
1269 		case '[':
1270 			if (line[strlen(line) - 1] != ']') {
1271 				qlog_parser(ctx, "%s:%d: Closing ] missing '%s'\n",
1272 					    path, lineno, line);
1273 				goto out;
1274 			}
1275 
1276 			if (state != STATE_SECTION &&
1277 			    state != STATE_VALUE_OR_SECTION) {
1278 				qlog_parser(ctx, "%s:%d: expected section before %s\n",
1279 					  path, lineno, line);
1280 				goto out;
1281 			}
1282 			if (section &&
1283 			    (!section->has_match || !section->has_property)) {
1284 				qlog_parser(ctx, "%s:%d: previous section %s was empty\n",
1285 					  path, lineno, section->name);
1286 				goto out; /* Previous section was empty */
1287 			}
1288 
1289 			state = STATE_MATCH;
1290 			section = section_new(path, line);
1291 			list_append(&ctx->sections, &section->link);
1292 			break;
1293 		default:
1294 			/* entries must start with A-Z */
1295 			if (line[0] < 'A' || line[0] > 'Z') {
1296 				qlog_parser(ctx, "%s:%d: Unexpected line %s\n",
1297 						 path, lineno, line);
1298 				goto out;
1299 			}
1300 			switch (state) {
1301 			case STATE_SECTION:
1302 				qlog_parser(ctx, "%s:%d: expected [Section], got %s\n",
1303 					  path, lineno, line);
1304 				goto out;
1305 			case STATE_MATCH:
1306 				if (!strstartswith(line, "Match")) {
1307 					qlog_parser(ctx, "%s:%d: expected MatchFoo=bar, have %s\n",
1308 							 path, lineno, line);
1309 					goto out;
1310 				}
1311 				state = STATE_MATCH_OR_VALUE;
1312 				break;
1313 			case STATE_MATCH_OR_VALUE:
1314 				if (!strstartswith(line, "Match"))
1315 					state = STATE_VALUE_OR_SECTION;
1316 				break;
1317 			case STATE_VALUE_OR_SECTION:
1318 				if (strstartswith(line, "Match")) {
1319 					qlog_parser(ctx, "%s:%d: expected value or [Section], have %s\n",
1320 							 path, lineno, line);
1321 					goto out;
1322 				}
1323 				break;
1324 			case STATE_ANY:
1325 				break;
1326 			}
1327 
1328 			if (!parse_value_line(ctx, section, line)) {
1329 				qlog_parser(ctx, "%s:%d: failed to parse %s\n",
1330 						 path, lineno, line);
1331 				goto out;
1332 			}
1333 			break;
1334 		}
1335 	}
1336 
1337 	if (!section) {
1338 		qlog_parser(ctx, "%s: is an empty file\n", path);
1339 		goto out;
1340 	}
1341 
1342 	if ((!section->has_match || !section->has_property)) {
1343 		qlog_parser(ctx, "%s:%d: previous section %s was empty\n",
1344 				 path, lineno, section->name);
1345 		goto out; /* Previous section was empty */
1346 	}
1347 
1348 	rc = true;
1349 out:
1350 	if (fp)
1351 		fclose(fp);
1352 
1353 	return rc;
1354 }
1355 
1356 static int
is_data_file(const struct dirent * dir)1357 is_data_file(const struct dirent *dir) {
1358 	return strendswith(dir->d_name, ".quirks");
1359 }
1360 
1361 static inline bool
parse_files(struct quirks_context * ctx,const char * data_path)1362 parse_files(struct quirks_context *ctx, const char *data_path)
1363 {
1364 	struct dirent **namelist;
1365 	int ndev = -1;
1366 	int idx = 0;
1367 
1368 	ndev = scandir(data_path, &namelist, is_data_file, versionsort);
1369 	if (ndev <= 0) {
1370 		qlog_error(ctx,
1371 			   "%s: failed to find data files\n",
1372 			   data_path);
1373 		return false;
1374 	}
1375 
1376 	for (idx = 0; idx < ndev; idx++) {
1377 		char path[PATH_MAX];
1378 
1379 		snprintf(path,
1380 			 sizeof(path),
1381 			 "%s/%s",
1382 			 data_path,
1383 			 namelist[idx]->d_name);
1384 
1385 		if (!parse_file(ctx, path))
1386 			break;
1387 	}
1388 
1389 	for (int i = 0; i < ndev; i++)
1390 		free(namelist[i]);
1391 	free(namelist);
1392 
1393 	return idx == ndev;
1394 }
1395 
1396 struct quirks_context *
quirks_init_subsystem(const char * data_path,const char * override_file,moused_log_handler log_handler,enum quirks_log_type log_type)1397 quirks_init_subsystem(const char *data_path,
1398 		      const char *override_file,
1399 		      moused_log_handler log_handler,
1400 		      enum quirks_log_type log_type)
1401 {
1402 	_unref_(quirks_context) *ctx = zalloc(sizeof *ctx);
1403 
1404 	assert(data_path);
1405 
1406 	ctx->refcount = 1;
1407 	ctx->log_handler = log_handler;
1408 	ctx->log_type = log_type;
1409 	list_init(&ctx->quirks);
1410 	list_init(&ctx->sections);
1411 
1412 	qlog_debug(ctx, "%s is data root\n", data_path);
1413 
1414 	ctx->dmi = init_dmi();
1415 	ctx->dt = init_dt();
1416 	if (!ctx->dmi && !ctx->dt)
1417 		return NULL;
1418 
1419 	if (!parse_files(ctx, data_path))
1420 		return NULL;
1421 
1422 	if (override_file && !parse_file(ctx, override_file))
1423 		return NULL;
1424 
1425 	return steal(&ctx);
1426 }
1427 
1428 struct quirks_context *
quirks_context_ref(struct quirks_context * ctx)1429 quirks_context_ref(struct quirks_context *ctx)
1430 {
1431 	assert(ctx->refcount > 0);
1432 	ctx->refcount++;
1433 
1434 	return ctx;
1435 }
1436 
1437 struct quirks_context *
quirks_context_unref(struct quirks_context * ctx)1438 quirks_context_unref(struct quirks_context *ctx)
1439 {
1440 	struct section *s;
1441 
1442 	if (!ctx)
1443 		return NULL;
1444 
1445 	assert(ctx->refcount >= 1);
1446 	ctx->refcount--;
1447 
1448 	if (ctx->refcount > 0)
1449 		return NULL;
1450 
1451 	/* Caller needs to clean up before calling this */
1452 	assert(list_empty(&ctx->quirks));
1453 
1454 	list_for_each_safe(s, &ctx->sections, link) {
1455 		section_destroy(s);
1456 	}
1457 
1458 	free(ctx->dmi);
1459 	free(ctx->dt);
1460 	free(ctx);
1461 
1462 	return NULL;
1463 }
1464 
1465 static struct quirks *
quirks_new(void)1466 quirks_new(void)
1467 {
1468 	struct quirks *q;
1469 
1470 	q = zalloc(sizeof *q);
1471 	q->refcount = 1;
1472 	q->nproperties = 0;
1473 	list_init(&q->link);
1474 	list_init(&q->floating_properties);
1475 
1476 	return q;
1477 }
1478 
1479 struct quirks *
quirks_unref(struct quirks * q)1480 quirks_unref(struct quirks *q)
1481 {
1482 	if (!q)
1483 		return NULL;
1484 
1485 	/* We don't really refcount, but might
1486 	 * as well have the API in place */
1487 	assert(q->refcount == 1);
1488 
1489 	for (size_t i = 0; i < q->nproperties; i++) {
1490 		property_unref(q->properties[i]);
1491 	}
1492 
1493 	/* Floating properties are owned by our quirks context, need to be
1494 	 * cleaned up here */
1495 	struct property *p;
1496 	list_for_each_safe(p, &q->floating_properties, link) {
1497 		property_cleanup(p);
1498 	}
1499 
1500 	list_remove(&q->link);
1501 	free(q->properties);
1502 	free(q);
1503 
1504 	return NULL;
1505 }
1506 
1507 static inline void
match_fill_name(struct match * m,struct device * device)1508 match_fill_name(struct match *m,
1509 		struct device *device)
1510 {
1511 	if (device->name[0] == 0)
1512 		return;
1513 
1514 	m->name = safe_strdup(device->name);
1515 
1516 	m->bits |= M_NAME;
1517 }
1518 
1519 static inline void
match_fill_uniq(struct match * m,struct device * device)1520 match_fill_uniq(struct match *m,
1521 		struct device *device)
1522 {
1523 	if (device->uniq[0] == 0)
1524 		return;
1525 
1526 	m->uniq = safe_strdup(device->uniq);
1527 
1528 	m->bits |= M_UNIQ;
1529 }
1530 
1531 static inline void
match_fill_bus_vid_pid(struct match * m,struct device * device)1532 match_fill_bus_vid_pid(struct match *m,
1533 		       struct device *device)
1534 {
1535 	m->product[0] = device->id.product;
1536 	m->product[1] = 0;
1537 	m->vendor = device->id.vendor;
1538 	m->version = device->id.version;
1539 	m->bits |= M_PID|M_VID|M_VERSION;
1540 	switch (device->id.bustype) {
1541 	case BUS_USB:
1542 		m->bus = BT_USB;
1543 		m->bits |= M_BUS;
1544 		break;
1545 	case BUS_BLUETOOTH:
1546 		m->bus = BT_BLUETOOTH;
1547 		m->bits |= M_BUS;
1548 		break;
1549 	case BUS_I8042:
1550 		m->bus = BT_PS2;
1551 		m->bits |= M_BUS;
1552 		break;
1553 	case BUS_RMI:
1554 		m->bus = BT_RMI;
1555 		m->bits |= M_BUS;
1556 		break;
1557 	case BUS_I2C:
1558 		m->bus = BT_I2C;
1559 		m->bits |= M_BUS;
1560 		break;
1561 	case BUS_SPI:
1562 		m->bus = BT_SPI;
1563 		m->bits |= M_BUS;
1564 		break;
1565 	default:
1566 		break;
1567 	}
1568 }
1569 
1570 static inline void
match_fill_udev_type(struct match * m,struct device * device)1571 match_fill_udev_type(struct match *m,
1572 		     struct device *device)
1573 {
1574 	switch (device->type) {
1575 	case DEVICE_TYPE_MOUSE:
1576 		m->udev_type |= UDEV_MOUSE;
1577 		break;
1578 	case DEVICE_TYPE_POINTINGSTICK:
1579 		m->udev_type |= UDEV_MOUSE | UDEV_POINTINGSTICK;
1580 		break;
1581 	case DEVICE_TYPE_TOUCHPAD:
1582 		m->udev_type |= UDEV_TOUCHPAD;
1583 		break;
1584 	case DEVICE_TYPE_TABLET:
1585 		m->udev_type |= UDEV_TABLET;
1586 		break;
1587 	case DEVICE_TYPE_TABLET_PAD:
1588 		m->udev_type |= UDEV_TABLET_PAD;
1589 		break;
1590 	case DEVICE_TYPE_KEYBOARD:
1591 		m->udev_type |= UDEV_KEYBOARD;
1592 		break;
1593 	case DEVICE_TYPE_JOYSTICK:
1594 		m->udev_type |= UDEV_JOYSTICK;
1595 		break;
1596 	default:
1597 		break;
1598 	}
1599 	m->bits |= M_UDEV_TYPE;
1600 }
1601 
1602 static inline void
match_fill_dmi_dt(struct match * m,char * dmi,char * dt)1603 match_fill_dmi_dt(struct match *m, char *dmi, char *dt)
1604 {
1605 	if (dmi) {
1606 		m->dmi = dmi;
1607 		m->bits |= M_DMI;
1608 	}
1609 
1610 	if (dt) {
1611 		m->dt = dt;
1612 		m->bits |= M_DT;
1613 	}
1614 }
1615 
1616 static struct match *
match_new(struct device * device,char * dmi,char * dt)1617 match_new(struct device *device,
1618 	  char *dmi, char *dt)
1619 {
1620 	struct match *m = zalloc(sizeof *m);
1621 
1622 	match_fill_name(m, device);
1623 	match_fill_uniq(m, device);
1624 	match_fill_bus_vid_pid(m, device);
1625 	match_fill_dmi_dt(m, dmi, dt);
1626 	match_fill_udev_type(m, device);
1627 	return m;
1628 }
1629 
1630 static void
match_free(struct match * m)1631 match_free(struct match *m)
1632 {
1633 	/* dmi and dt are global */
1634 	free(m->name);
1635 	free(m->uniq);
1636 	free(m);
1637 }
1638 
1639 static void
quirk_merge_event_codes(struct quirks_context * ctx,struct quirks * q,const struct property * property)1640 quirk_merge_event_codes(struct quirks_context *ctx,
1641 			struct quirks *q,
1642 			const struct property *property)
1643 {
1644 	for (size_t i = 0; i < q->nproperties; i++) {
1645 		struct property *p = q->properties[i];
1646 
1647 		if (p->id != property->id)
1648 			continue;
1649 
1650 		/* We have a duplicated property, merge in with ours */
1651 		size_t offset = p->value.tuples.ntuples;
1652 		size_t max = ARRAY_LENGTH(p->value.tuples.tuples);
1653 		for (size_t j = 0; j < property->value.tuples.ntuples; j++) {
1654 			if (offset + j >= max)
1655 				break;
1656 			p->value.tuples.tuples[offset + j] = property->value.tuples.tuples[j];
1657 			p->value.tuples.ntuples++;
1658 		}
1659 		return;
1660 	}
1661 
1662 	/* First time we add AttrEventCode: create a new property.
1663 	 * Unlike the other properties, this one isn't part of a section, it belongs
1664 	 * to the quirks */
1665 	struct property *newprop = property_new();
1666 	newprop->id = property->id;
1667 	newprop->type = property->type;
1668 	newprop->value.tuples = property->value.tuples;
1669 	/* Caller responsible for pre-allocating space */
1670 	q->properties[q->nproperties++] = property_ref(newprop);
1671 	list_append(&q->floating_properties, &newprop->link);
1672 }
1673 
1674 static void
quirk_apply_section(struct quirks_context * ctx,struct quirks * q,const struct section * s)1675 quirk_apply_section(struct quirks_context *ctx,
1676 		    struct quirks *q,
1677 		    const struct section *s)
1678 {
1679 	struct property *p;
1680 	size_t nprops = 0;
1681 	void *tmp;
1682 
1683 	list_for_each(p, &s->properties, link) {
1684 		nprops++;
1685 	}
1686 
1687 	nprops += q->nproperties;
1688 	tmp = realloc(q->properties, nprops * sizeof(p));
1689 	if (!tmp)
1690 		return;
1691 
1692 	q->properties = tmp;
1693 	list_for_each(p, &s->properties, link) {
1694 		qlog_debug(ctx, "property added: %s from %s\n",
1695 			   quirk_get_name(p->id), s->name);
1696 
1697 		/* All quirks but AttrEventCode and AttrInputProp
1698 		 * simply overwrite each other, so we can just append the
1699 		 * matching property and, later when checking the quirk, pick
1700 		 * the last one in the array.
1701 		 *
1702 		 * The event codes/input props are special because they're lists
1703 		 * that may *partially* override each other, e.g. a section may
1704 		 * enable BTN_LEFT and BTN_RIGHT but a later section may disable
1705 		 * only BTN_RIGHT. This should result in BTN_LEFT force-enabled
1706 		 * and BTN_RIGHT force-disabled.
1707 		 *
1708 		 * To hack around this, those are the only ones where only ever
1709 		 * have one struct property in the list (not owned by a section)
1710 		 * and we simply merge any extra sections onto that.
1711 		 */
1712 		if (p->id == QUIRK_ATTR_EVENT_CODE ||
1713 		    p->id == QUIRK_ATTR_INPUT_PROP)
1714 			quirk_merge_event_codes(ctx, q, p);
1715 		else
1716 			q->properties[q->nproperties++] = property_ref(p);
1717 	}
1718 }
1719 
1720 static bool
quirk_match_section(struct quirks_context * ctx,struct quirks * q,struct section * s,struct match * m,struct device * device)1721 quirk_match_section(struct quirks_context *ctx,
1722 		    struct quirks *q,
1723 		    struct section *s,
1724 		    struct match *m,
1725 		    struct device *device)
1726 {
1727 	uint32_t matched_flags = 0x0;
1728 
1729 	for (uint32_t flag = 0x1; flag <= M_LAST; flag <<= 1) {
1730 		uint32_t prev_matched_flags = matched_flags;
1731 		/* section doesn't have this bit set, continue */
1732 		if ((s->match.bits & flag) == 0)
1733 			continue;
1734 
1735 		/* Couldn't fill in this bit for the match, so we
1736 		 * do not match on it */
1737 		if ((m->bits & flag) == 0) {
1738 			qlog_debug(ctx,
1739 				   "%s wants %s but we don't have that\n",
1740 				   s->name, matchflagname(flag));
1741 			continue;
1742 		}
1743 
1744 		/* now check the actual matching bit */
1745 		switch (flag) {
1746 		case M_NAME:
1747 			if (fnmatch(s->match.name, m->name, 0) == 0)
1748 				matched_flags |= flag;
1749 			break;
1750 		case M_UNIQ:
1751 			if (fnmatch(s->match.uniq, m->uniq, 0) == 0)
1752 				matched_flags |= flag;
1753 			break;
1754 		case M_BUS:
1755 			if (m->bus == s->match.bus)
1756 				matched_flags |= flag;
1757 			break;
1758 		case M_VID:
1759 			if (m->vendor == s->match.vendor)
1760 				matched_flags |= flag;
1761 			break;
1762 		case M_PID:
1763 			ARRAY_FOR_EACH(m->product, mi) {
1764 				if (*mi == 0 || matched_flags & flag)
1765 					break;
1766 
1767 				ARRAY_FOR_EACH(s->match.product, si) {
1768 					if (*si == 0)
1769 						break;
1770 					if (*mi == *si) {
1771 						matched_flags |= flag;
1772 						break;
1773 					}
1774 				}
1775 			}
1776 			break;
1777 		case M_VERSION:
1778 			if (m->version == s->match.version)
1779 				matched_flags |= flag;
1780 			break;
1781 		case M_DMI:
1782 			if (fnmatch(s->match.dmi, m->dmi, 0) == 0)
1783 				matched_flags |= flag;
1784 			break;
1785 		case M_DT:
1786 			if (fnmatch(s->match.dt, m->dt, 0) == 0)
1787 				matched_flags |= flag;
1788 			break;
1789 		case M_UDEV_TYPE:
1790 			if (s->match.udev_type & m->udev_type)
1791 				matched_flags |= flag;
1792 			break;
1793 		default:
1794 			abort();
1795 		}
1796 
1797 		if (prev_matched_flags != matched_flags) {
1798 			qlog_debug(ctx,
1799 				   "%s matches for %s\n",
1800 				   s->name,
1801 				   matchflagname(flag));
1802 		}
1803 	}
1804 
1805 	if (s->match.bits == matched_flags) {
1806 		qlog_debug(ctx, "%s is full match\n", s->name);
1807 		quirk_apply_section(ctx, q, s);
1808 	}
1809 
1810 	return true;
1811 }
1812 
1813 struct quirks *
quirks_fetch_for_device(struct quirks_context * ctx,struct device * device)1814 quirks_fetch_for_device(struct quirks_context *ctx,
1815 			struct device *device)
1816 {
1817 	struct section *s;
1818 	struct match *m;
1819 
1820 	if (!ctx)
1821 		return NULL;
1822 
1823 	qlog_debug(ctx, "%s: fetching quirks\n", device->path);
1824 
1825 	_unref_(quirks) *q = quirks_new();
1826 
1827 	m = match_new(device, ctx->dmi, ctx->dt);
1828 
1829 	list_for_each(s, &ctx->sections, link) {
1830 		quirk_match_section(ctx, q, s, m, device);
1831 	}
1832 
1833 	match_free(m);
1834 
1835 	if (q->nproperties == 0) {
1836 		return NULL;
1837 	}
1838 
1839 	list_insert(&ctx->quirks, &q->link);
1840 
1841 	return steal(&q);
1842 }
1843 
1844 static inline struct property *
quirk_find_prop(struct quirks * q,enum quirk which)1845 quirk_find_prop(struct quirks *q, enum quirk which)
1846 {
1847 	/* Run backwards to only handle the last one assigned */
1848 	for (ssize_t i = q->nproperties - 1; i >= 0; i--) {
1849 		struct property *p = q->properties[i];
1850 		if (p->id == which)
1851 			return p;
1852 	}
1853 
1854 	return NULL;
1855 }
1856 
1857 bool
quirks_has_quirk(struct quirks * q,enum quirk which)1858 quirks_has_quirk(struct quirks *q, enum quirk which)
1859 {
1860 	return quirk_find_prop(q, which) != NULL;
1861 }
1862 
1863 bool
quirks_get_int32(struct quirks * q,enum quirk which,int32_t * val)1864 quirks_get_int32(struct quirks *q, enum quirk which, int32_t *val)
1865 {
1866 	struct property *p;
1867 
1868 	if (!q)
1869 		return false;
1870 
1871 	p = quirk_find_prop(q, which);
1872 	if (!p)
1873 		return false;
1874 
1875 	assert(p->type == PT_INT);
1876 	*val = p->value.i;
1877 
1878 	return true;
1879 }
1880 
1881 bool
quirks_get_uint32(struct quirks * q,enum quirk which,uint32_t * val)1882 quirks_get_uint32(struct quirks *q, enum quirk which, uint32_t *val)
1883 {
1884 	struct property *p;
1885 
1886 	if (!q)
1887 		return false;
1888 
1889 	p = quirk_find_prop(q, which);
1890 	if (!p)
1891 		return false;
1892 
1893 	assert(p->type == PT_UINT);
1894 	*val = p->value.u;
1895 
1896 	return true;
1897 }
1898 
1899 bool
quirks_get_double(struct quirks * q,enum quirk which,double * val)1900 quirks_get_double(struct quirks *q, enum quirk which, double *val)
1901 {
1902 	struct property *p;
1903 
1904 	if (!q)
1905 		return false;
1906 
1907 	p = quirk_find_prop(q, which);
1908 	if (!p)
1909 		return false;
1910 
1911 	assert(p->type == PT_DOUBLE);
1912 	*val = p->value.d;
1913 
1914 	return true;
1915 }
1916 
1917 bool
quirks_get_string(struct quirks * q,enum quirk which,char ** val)1918 quirks_get_string(struct quirks *q, enum quirk which, char **val)
1919 {
1920 	struct property *p;
1921 
1922 	if (!q)
1923 		return false;
1924 
1925 	p = quirk_find_prop(q, which);
1926 	if (!p)
1927 		return false;
1928 
1929 	assert(p->type == PT_STRING);
1930 	*val = p->value.s;
1931 
1932 	return true;
1933 }
1934 
1935 bool
quirks_get_bool(struct quirks * q,enum quirk which,bool * val)1936 quirks_get_bool(struct quirks *q, enum quirk which, bool *val)
1937 {
1938 	struct property *p;
1939 
1940 	if (!q)
1941 		return false;
1942 
1943 	p = quirk_find_prop(q, which);
1944 	if (!p)
1945 		return false;
1946 
1947 	assert(p->type == PT_BOOL);
1948 	*val = p->value.b;
1949 
1950 	return true;
1951 }
1952 
1953 bool
quirks_get_dimensions(struct quirks * q,enum quirk which,struct quirk_dimensions * val)1954 quirks_get_dimensions(struct quirks *q,
1955 		      enum quirk which,
1956 		      struct quirk_dimensions *val)
1957 {
1958 	struct property *p;
1959 
1960 	if (!q)
1961 		return false;
1962 
1963 	p = quirk_find_prop(q, which);
1964 	if (!p)
1965 		return false;
1966 
1967 	assert(p->type == PT_DIMENSION);
1968 	*val = p->value.dim;
1969 
1970 	return true;
1971 }
1972 
1973 bool
quirks_get_range(struct quirks * q,enum quirk which,struct quirk_range * val)1974 quirks_get_range(struct quirks *q,
1975 		 enum quirk which,
1976 		 struct quirk_range *val)
1977 {
1978 	struct property *p;
1979 
1980 	if (!q)
1981 		return false;
1982 
1983 	p = quirk_find_prop(q, which);
1984 	if (!p)
1985 		return false;
1986 
1987 	assert(p->type == PT_RANGE);
1988 	*val = p->value.range;
1989 
1990 	return true;
1991 }
1992 
1993 bool
quirks_get_tuples(struct quirks * q,enum quirk which,const struct quirk_tuples ** tuples)1994 quirks_get_tuples(struct quirks *q,
1995 		  enum quirk which,
1996 		  const struct quirk_tuples **tuples)
1997 {
1998 	struct property *p;
1999 
2000 	if (!q)
2001 		return false;
2002 
2003 	p = quirk_find_prop(q, which);
2004 	if (!p)
2005 		return false;
2006 
2007 	assert(p->type == PT_TUPLES);
2008 	*tuples = &p->value.tuples;
2009 
2010 	return true;
2011 }
2012 
2013 bool
quirks_get_uint32_array(struct quirks * q,enum quirk which,const uint32_t ** array,size_t * nelements)2014 quirks_get_uint32_array(struct quirks *q,
2015 			enum quirk which,
2016 			const uint32_t **array,
2017 			size_t *nelements)
2018 {
2019 	struct property *p;
2020 
2021 	if (!q)
2022 		return false;
2023 
2024 	p = quirk_find_prop(q, which);
2025 	if (!p)
2026 		return false;
2027 
2028 	assert(p->type == PT_UINT_ARRAY);
2029 	*array = p->value.array.data.u;
2030 	*nelements = p->value.array.nelements;
2031 
2032 	return true;
2033 }
2034