2753 lines · 77.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* *  HID driver for multitouch panels * *  Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr> *  Copyright (c) 2010-2013 Benjamin Tissoires <benjamin.tissoires@gmail.com> *  Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France *  Copyright (c) 2012-2013 Red Hat, Inc * *  This code is partly based on hid-egalax.c: * *  Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> *  Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> *  Copyright (c) 2010 Canonical, Ltd. * *  This code is partly based on hid-3m-pct.c: * *  Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr> *  Copyright (c) 2010      Henrik Rydberg <rydberg@euromail.se> *  Copyright (c) 2010      Canonical, Ltd. */ /* */ /* * This driver is regularly tested thanks to the test suite in hid-tools[1]. * Please run these regression tests before patching this module so that * your patch won't break existing known devices. * * [1] https://gitlab.freedesktop.org/libevdev/hid-tools */ #include <linux/bitmap.h>#include <linux/bits.h>#include <linux/device.h>#include <linux/hid.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/input/mt.h>#include <linux/jiffies.h>#include <linux/string.h>#include <linux/timer.h>  MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");MODULE_DESCRIPTION("HID multitouch panels");MODULE_LICENSE("GPL"); #include "hid-ids.h" #include "hid-haptic.h" /* quirks to control the device */#define MT_QUIRK_NOT_SEEN_MEANS_UP	BIT(0)#define MT_QUIRK_SLOT_IS_CONTACTID	BIT(1)#define MT_QUIRK_CYPRESS		BIT(2)#define MT_QUIRK_SLOT_IS_CONTACTNUMBER	BIT(3)#define MT_QUIRK_ALWAYS_VALID		BIT(4)#define MT_QUIRK_VALID_IS_INRANGE	BIT(5)#define MT_QUIRK_VALID_IS_CONFIDENCE	BIT(6)#define MT_QUIRK_CONFIDENCE		BIT(7)#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE	BIT(8)#define MT_QUIRK_NO_AREA		BIT(9)#define MT_QUIRK_IGNORE_DUPLICATES	BIT(10)#define MT_QUIRK_HOVERING		BIT(11)#define MT_QUIRK_CONTACT_CNT_ACCURATE	BIT(12)#define MT_QUIRK_FORCE_GET_FEATURE	BIT(13)#define MT_QUIRK_FIX_CONST_CONTACT_ID	BIT(14)#define MT_QUIRK_TOUCH_SIZE_SCALING	BIT(15)#define MT_QUIRK_STICKY_FINGERS		BIT(16)#define MT_QUIRK_ASUS_CUSTOM_UP		BIT(17)#define MT_QUIRK_WIN8_PTP_BUTTONS	BIT(18)#define MT_QUIRK_SEPARATE_APP_REPORT	BIT(19)#define MT_QUIRK_FORCE_MULTI_INPUT	BIT(20)#define MT_QUIRK_DISABLE_WAKEUP		BIT(21)#define MT_QUIRK_ORIENTATION_INVERT	BIT(22)#define MT_QUIRK_APPLE_TOUCHBAR		BIT(23)#define MT_QUIRK_YOGABOOK9I		BIT(24)#define MT_QUIRK_KEEP_LATENCY_ON_CLOSE	BIT(25) #define MT_INPUTMODE_TOUCHSCREEN	0x02#define MT_INPUTMODE_TOUCHPAD		0x03 #define MT_BUTTONTYPE_CLICKPAD		0#define MT_BUTTONTYPE_PRESSUREPAD	1 enum latency_mode {	HID_LATENCY_NORMAL = 0,	HID_LATENCY_HIGH = 1,}; enum report_mode {	TOUCHPAD_REPORT_NONE = 0,	TOUCHPAD_REPORT_BUTTONS = BIT(0),	TOUCHPAD_REPORT_CONTACTS = BIT(1),	TOUCHPAD_REPORT_ALL = TOUCHPAD_REPORT_BUTTONS | TOUCHPAD_REPORT_CONTACTS,}; #define MT_IO_FLAGS_RUNNING		0 static const bool mtrue = true;		/* default for true */static const bool mfalse;		/* default for false */static const __s32 mzero;		/* default for 0 */ #define DEFAULT_TRUE	((void *)&mtrue)#define DEFAULT_FALSE	((void *)&mfalse)#define DEFAULT_ZERO	((void *)&mzero) struct mt_usages {	struct list_head list;	__s32 *x, *y, *cx, *cy, *p, *w, *h, *a;	__s32 *contactid;	/* the device ContactID assigned to this slot */	bool *tip_state;	/* is the touch valid? */	bool *inrange_state;	/* is the finger in proximity of the sensor? */	bool *confidence_state;	/* is the touch made by a finger? */}; struct mt_application {	struct list_head list;	unsigned int application;	unsigned int report_id;	struct list_head mt_usages;	/* mt usages list */ 	__s32 quirks; 	__s32 *scantime;		/* scantime reported */	__s32 scantime_logical_max;	/* max value for raw scantime */ 	__s32 *raw_cc;			/* contact count in the report */	int left_button_state;		/* left button state */	unsigned int mt_flags;		/* flags to pass to input-mt */ 	unsigned long *pending_palm_slots;	/* slots where we reported palm						 * and need to release */ 	__u8 num_received;	/* how many contacts we received */	__u8 num_expected;	/* expected last contact index */	__u8 buttons_count;	/* number of physical buttons per touchpad */	__u8 touches_by_report;	/* how many touches are present in one report:				 * 1 means we should use a serial protocol				 * > 1 means hybrid (multitouch) protocol				 */ 	unsigned long jiffies;	/* the frame's jiffies */	int timestamp;		/* the timestamp to be sent */	int prev_scantime;		/* scantime reported previously */ 	bool have_contact_count;}; struct mt_class {	__s32 name;	/* MT_CLS */	__s32 quirks;	__s32 sn_move;	/* Signal/noise ratio for move events */	__s32 sn_width;	/* Signal/noise ratio for width events */	__s32 sn_height;	/* Signal/noise ratio for height events */	__s32 sn_pressure;	/* Signal/noise ratio for pressure events */	__u8 maxcontacts;	bool is_indirect;	/* true for touchpads */	bool export_all_inputs;	/* do not ignore mouse, keyboards, etc... */}; struct mt_report_data {	struct list_head list;	struct hid_report *report;	struct mt_application *application;	bool is_mt_collection;}; struct mt_device {	struct mt_class mtclass;	/* our mt device class */	struct timer_list release_timer;	/* to release sticky fingers */	struct hid_haptic_device *haptic;	/* haptic related configuration */	struct hid_device *hdev;	/* hid_device we're attached to */	unsigned long mt_io_flags;	/* mt flags (MT_IO_FLAGS_RUNNING) */	unsigned long *active_slots;	/* bitmap of slots with an active					 * contact, sized for maxcontacts					 */	__u8 inputmode_value;	/* InputMode HID feature value */	__u8 maxcontacts;	bool is_buttonpad;	/* is this device a button pad? */	bool is_pressurepad;	/* is this device a pressurepad? */	bool is_haptic_touchpad;	/* is this device a haptic touchpad? */	bool serial_maybe;	/* need to check for serial protocol */ 	struct list_head applications;	struct list_head reports;}; static void mt_post_parse_default_settings(struct mt_device *td,					   struct mt_application *app);static void mt_post_parse(struct mt_device *td, struct mt_application *app); /* classes of device behavior */#define MT_CLS_DEFAULT				0x0001 #define MT_CLS_SERIAL				0x0002#define MT_CLS_CONFIDENCE			0x0003#define MT_CLS_CONFIDENCE_CONTACT_ID		0x0004#define MT_CLS_CONFIDENCE_MINUS_ONE		0x0005#define MT_CLS_DUAL_INRANGE_CONTACTID		0x0006#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER	0x0007/* reserved					0x0008 */#define MT_CLS_INRANGE_CONTACTNUMBER		0x0009#define MT_CLS_NSMU				0x000a/* reserved					0x0010 *//* reserved					0x0011 */#define MT_CLS_WIN_8				0x0012#define MT_CLS_EXPORT_ALL_INPUTS		0x0013/* reserved					0x0014 */#define MT_CLS_WIN_8_FORCE_MULTI_INPUT		0x0015#define MT_CLS_WIN_8_DISABLE_WAKEUP		0x0016#define MT_CLS_WIN_8_NO_STICKY_FINGERS		0x0017#define MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU	0x0018#define MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE	0x0019 /* vendor specific classes */#define MT_CLS_3M				0x0101/* reserved					0x0102 */#define MT_CLS_EGALAX				0x0103#define MT_CLS_EGALAX_SERIAL			0x0104#define MT_CLS_TOPSEED				0x0105#define MT_CLS_PANASONIC			0x0106#define MT_CLS_FLATFROG				0x0107#define MT_CLS_GENERALTOUCH_TWOFINGERS		0x0108#define MT_CLS_GENERALTOUCH_PWT_TENFINGERS	0x0109#define MT_CLS_LG				0x010a#define MT_CLS_ASUS				0x010b#define MT_CLS_VTL				0x0110#define MT_CLS_GOOGLE				0x0111#define MT_CLS_RAZER_BLADE_STEALTH		0x0112#define MT_CLS_SMART_TECH			0x0113#define MT_CLS_APPLE_TOUCHBAR			0x0114#define MT_CLS_YOGABOOK9I			0x0115#define MT_CLS_EGALAX_P80H84			0x0116#define MT_CLS_SIS				0x0457 #define MT_DEFAULT_MAXCONTACT	10#define MT_MAX_MAXCONTACT	250 /* * Resync device and local timestamps after that many microseconds without * receiving data. */#define MAX_TIMESTAMP_INTERVAL	1000000 #define MT_USB_DEVICE(v, p)	HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p)#define MT_BT_DEVICE(v, p)	HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p) /* * these device-dependent functions determine what slot corresponds * to a valid contact that was just read. */ static int cypress_compute_slot(struct mt_application *application,				struct mt_usages *slot){	if (*slot->contactid != 0 || application->num_received == 0)		return *slot->contactid;	else		return -1;} static const struct mt_class mt_classes[] = {	{ .name = MT_CLS_DEFAULT,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_CONTACT_CNT_ACCURATE },	{ .name = MT_CLS_NSMU,		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },	{ .name = MT_CLS_SERIAL,		.quirks = MT_QUIRK_ALWAYS_VALID},	{ .name = MT_CLS_CONFIDENCE,		.quirks = MT_QUIRK_VALID_IS_CONFIDENCE },	{ .name = MT_CLS_CONFIDENCE_CONTACT_ID,		.quirks = MT_QUIRK_VALID_IS_CONFIDENCE |			MT_QUIRK_SLOT_IS_CONTACTID },	{ .name = MT_CLS_CONFIDENCE_MINUS_ONE,		.quirks = MT_QUIRK_VALID_IS_CONFIDENCE |			MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE },	{ .name = MT_CLS_DUAL_INRANGE_CONTACTID,		.quirks = MT_QUIRK_VALID_IS_INRANGE |			MT_QUIRK_SLOT_IS_CONTACTID,		.maxcontacts = 2 },	{ .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,		.quirks = MT_QUIRK_VALID_IS_INRANGE |			MT_QUIRK_SLOT_IS_CONTACTNUMBER,		.maxcontacts = 2 },	{ .name = MT_CLS_INRANGE_CONTACTNUMBER,		.quirks = MT_QUIRK_VALID_IS_INRANGE |			MT_QUIRK_SLOT_IS_CONTACTNUMBER },	{ .name = MT_CLS_WIN_8,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_IGNORE_DUPLICATES |			MT_QUIRK_HOVERING |			MT_QUIRK_CONTACT_CNT_ACCURATE |			MT_QUIRK_STICKY_FINGERS |			MT_QUIRK_WIN8_PTP_BUTTONS,		.export_all_inputs = true },	{ .name = MT_CLS_EXPORT_ALL_INPUTS,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_CONTACT_CNT_ACCURATE,		.export_all_inputs = true },	{ .name = MT_CLS_WIN_8_FORCE_MULTI_INPUT,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_IGNORE_DUPLICATES |			MT_QUIRK_HOVERING |			MT_QUIRK_CONTACT_CNT_ACCURATE |			MT_QUIRK_STICKY_FINGERS |			MT_QUIRK_WIN8_PTP_BUTTONS |			MT_QUIRK_FORCE_MULTI_INPUT,		.export_all_inputs = true },	{ .name = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU,		.quirks = MT_QUIRK_IGNORE_DUPLICATES |			MT_QUIRK_HOVERING |			MT_QUIRK_CONTACT_CNT_ACCURATE |			MT_QUIRK_STICKY_FINGERS |			MT_QUIRK_WIN8_PTP_BUTTONS |			MT_QUIRK_FORCE_MULTI_INPUT |			MT_QUIRK_NOT_SEEN_MEANS_UP,		.export_all_inputs = true },	{ .name = MT_CLS_WIN_8_DISABLE_WAKEUP,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_IGNORE_DUPLICATES |			MT_QUIRK_HOVERING |			MT_QUIRK_CONTACT_CNT_ACCURATE |			MT_QUIRK_STICKY_FINGERS |			MT_QUIRK_WIN8_PTP_BUTTONS |			MT_QUIRK_DISABLE_WAKEUP,		.export_all_inputs = true },	{ .name = MT_CLS_WIN_8_NO_STICKY_FINGERS,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_IGNORE_DUPLICATES |			MT_QUIRK_HOVERING |			MT_QUIRK_CONTACT_CNT_ACCURATE |			MT_QUIRK_WIN8_PTP_BUTTONS,		.export_all_inputs = true },	{ .name = MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_IGNORE_DUPLICATES |			MT_QUIRK_HOVERING |			MT_QUIRK_CONTACT_CNT_ACCURATE |			MT_QUIRK_STICKY_FINGERS |			MT_QUIRK_WIN8_PTP_BUTTONS |			MT_QUIRK_KEEP_LATENCY_ON_CLOSE,		.export_all_inputs = true }, 	/*	 * vendor specific classes	 */	{ .name = MT_CLS_3M,		.quirks = MT_QUIRK_VALID_IS_CONFIDENCE |			MT_QUIRK_SLOT_IS_CONTACTID |			MT_QUIRK_TOUCH_SIZE_SCALING,		.sn_move = 2048,		.sn_width = 128,		.sn_height = 128,		.maxcontacts = 60,	},	{ .name = MT_CLS_EGALAX,		.quirks =  MT_QUIRK_SLOT_IS_CONTACTID |			MT_QUIRK_VALID_IS_INRANGE,		.sn_move = 4096,		.sn_pressure = 32,	},	{ .name = MT_CLS_EGALAX_SERIAL,		.quirks =  MT_QUIRK_SLOT_IS_CONTACTID |			MT_QUIRK_ALWAYS_VALID,		.sn_move = 4096,		.sn_pressure = 32,	},	{ .name = MT_CLS_TOPSEED,		.quirks = MT_QUIRK_ALWAYS_VALID,		.is_indirect = true,		.maxcontacts = 2,	},	{ .name = MT_CLS_PANASONIC,		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP,		.maxcontacts = 4 },	{ .name	= MT_CLS_GENERALTOUCH_TWOFINGERS,		.quirks	= MT_QUIRK_NOT_SEEN_MEANS_UP |			MT_QUIRK_VALID_IS_INRANGE |			MT_QUIRK_SLOT_IS_CONTACTID,		.maxcontacts = 2	},	{ .name	= MT_CLS_GENERALTOUCH_PWT_TENFINGERS,		.quirks	= MT_QUIRK_NOT_SEEN_MEANS_UP |			MT_QUIRK_SLOT_IS_CONTACTID	}, 	{ .name = MT_CLS_FLATFROG,		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |			MT_QUIRK_NO_AREA,		.sn_move = 2048,		.maxcontacts = 40,	},	{ .name = MT_CLS_LG,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_FIX_CONST_CONTACT_ID |			MT_QUIRK_IGNORE_DUPLICATES |			MT_QUIRK_HOVERING |			MT_QUIRK_CONTACT_CNT_ACCURATE },	{ .name = MT_CLS_ASUS,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_CONTACT_CNT_ACCURATE |			MT_QUIRK_ASUS_CUSTOM_UP },	{ .name = MT_CLS_VTL,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_CONTACT_CNT_ACCURATE |			MT_QUIRK_STICKY_FINGERS |			MT_QUIRK_FORCE_GET_FEATURE,	},	{ .name = MT_CLS_GOOGLE,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_CONTACT_CNT_ACCURATE |			MT_QUIRK_SLOT_IS_CONTACTID |			MT_QUIRK_HOVERING	},	{ .name = MT_CLS_RAZER_BLADE_STEALTH,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_IGNORE_DUPLICATES |			MT_QUIRK_HOVERING |			MT_QUIRK_CONTACT_CNT_ACCURATE |			MT_QUIRK_WIN8_PTP_BUTTONS,	},	{ .name = MT_CLS_SMART_TECH,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_IGNORE_DUPLICATES |			MT_QUIRK_CONTACT_CNT_ACCURATE |			MT_QUIRK_SEPARATE_APP_REPORT,	},	{ .name = MT_CLS_APPLE_TOUCHBAR,		.quirks = MT_QUIRK_HOVERING |			MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE |			MT_QUIRK_APPLE_TOUCHBAR,		.maxcontacts = 11,	},	{ .name = MT_CLS_SIS,		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |			MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_CONTACT_CNT_ACCURATE,	},		{ .name = MT_CLS_YOGABOOK9I,		.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |			MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_CONTACT_CNT_ACCURATE |			MT_QUIRK_FORCE_MULTI_INPUT |			MT_QUIRK_SEPARATE_APP_REPORT |			MT_QUIRK_HOVERING |			MT_QUIRK_YOGABOOK9I,		.maxcontacts = 10,		.export_all_inputs = true	},	{ .name = MT_CLS_EGALAX_P80H84,		.quirks = MT_QUIRK_ALWAYS_VALID |			MT_QUIRK_IGNORE_DUPLICATES |			MT_QUIRK_CONTACT_CNT_ACCURATE,	},	{ }}; static ssize_t mt_show_quirks(struct device *dev,			   struct device_attribute *attr,			   char *buf){	struct hid_device *hdev = to_hid_device(dev);	struct mt_device *td = hid_get_drvdata(hdev); 	return sprintf(buf, "%u\n", td->mtclass.quirks);} static ssize_t mt_set_quirks(struct device *dev,			  struct device_attribute *attr,			  const char *buf, size_t count){	struct hid_device *hdev = to_hid_device(dev);	struct mt_device *td = hid_get_drvdata(hdev);	struct mt_application *application; 	unsigned long val; 	if (kstrtoul(buf, 0, &val))		return -EINVAL; 	td->mtclass.quirks = val; 	list_for_each_entry(application, &td->applications, list) {		application->quirks = val;		if (!application->have_contact_count)			application->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;	} 	return count;} static DEVICE_ATTR(quirks, S_IWUSR | S_IRUGO, mt_show_quirks, mt_set_quirks); static struct attribute *sysfs_attrs[] = {	&dev_attr_quirks.attr,

Lines 1–500 of 2753.