Commit 8d0bf790 authored by Angela Czubak's avatar Angela Czubak Committed by Benjamin Tissoires
Browse files

HID: multitouch: add haptic multitouch support



If CONFIG_HID_HAPTIC is enabled, and the device is recognized to have
simple haptic capabilities, try initializing the haptic device, check
input frames for pressure and handle it using hid_haptic_* API.

Signed-off-by: default avatarAngela Czubak <aczubak@google.com>
Co-developed-by: default avatarJonathan Denose <jdenose@google.com>
Signed-off-by: default avatarJonathan Denose <jdenose@google.com>
Signed-off-by: default avatarBenjamin Tissoires <bentiss@kernel.org>
parent ff66b8ee
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -103,19 +103,25 @@ int hid_haptic_input_configured(struct hid_device *hdev,
{
	return 0;
}
static inline
void hid_haptic_reset(struct hid_device *hdev, struct hid_haptic_device *haptic)
{}
static inline
int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_ptr)
{
	return 0;
}
static inline
void hid_haptic_handle_press_release(struct hid_haptic_device *haptic)
{}
void hid_haptic_handle_press_release(struct hid_haptic_device *haptic) {}
static inline
void hid_haptic_pressure_reset(struct hid_haptic_device *haptic)
{}
bool hid_haptic_handle_input(struct hid_haptic_device *haptic)
{
	return false;
}
static inline
void hid_haptic_pressure_reset(struct hid_haptic_device *haptic) {}
static inline
void hid_haptic_pressure_increase(struct hid_haptic_device *haptic,
				  __s32 pressure)
{}
#endif
+47 −0
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ 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)
@@ -168,11 +170,13 @@ struct mt_report_data {
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_*) */
	__u8 inputmode_value;	/* InputMode HID feature value */
	__u8 maxcontacts;
	bool is_buttonpad;	/* is this device a button pad? */
	bool is_haptic_touchpad;	/* is this device a haptic touchpad? */
	bool serial_maybe;	/* need to check for serial protocol */

	struct list_head applications;
@@ -533,6 +537,8 @@ static void mt_feature_mapping(struct hid_device *hdev,
			mt_get_feature(hdev, field->report);
		break;
	}

	hid_haptic_feature_mapping(hdev, td->haptic, field, usage);
}

static void set_abs(struct input_dev *input, unsigned int code,
@@ -888,6 +894,9 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
		case HID_DG_TIPPRESSURE:
			set_abs(hi->input, ABS_MT_PRESSURE, field,
				cls->sn_pressure);
			td->is_haptic_touchpad =
				hid_haptic_check_pressure_unit(td->haptic,
							       hi, field);
			MT_STORE_FIELD(p);
			return 1;
		case HID_DG_SCANTIME:
@@ -1008,6 +1017,8 @@ static void mt_sync_frame(struct mt_device *td, struct mt_application *app,

	app->num_received = 0;
	app->left_button_state = 0;
	if (td->is_haptic_touchpad)
		hid_haptic_pressure_reset(td->haptic);

	if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags))
		set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags);
@@ -1165,6 +1176,9 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
			minor = minor >> 1;
		}

		if (td->is_haptic_touchpad)
			hid_haptic_pressure_increase(td->haptic, *slot->p);

		x = hdev->quirks & HID_QUIRK_X_INVERT ?
			input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->x :
			*slot->x;
@@ -1366,6 +1380,9 @@ static int mt_touch_input_configured(struct hid_device *hdev,
	if (cls->is_indirect)
		app->mt_flags |= INPUT_MT_POINTER;

	if (td->is_haptic_touchpad)
		app->mt_flags |= INPUT_MT_TOTAL_FORCE;

	if (app->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
		app->mt_flags |= INPUT_MT_DROP_UNUSED;

@@ -1401,6 +1418,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
	struct mt_device *td = hid_get_drvdata(hdev);
	struct mt_application *application;
	struct mt_report_data *rdata;
	int ret;

	rdata = mt_find_report_data(td, field->report);
	if (!rdata) {
@@ -1463,6 +1481,11 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
	if (field->physical == HID_DG_STYLUS)
		hi->application = HID_DG_STYLUS;

	ret = hid_haptic_input_mapping(hdev, td->haptic, hi, field, usage, bit,
				       max);
	if (ret != 0)
		return ret;

	/* let hid-core decide for the others */
	return 0;
}
@@ -1685,6 +1708,14 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
	struct hid_report *report;
	int ret;

	if (td->is_haptic_touchpad && (td->mtclass.name == MT_CLS_WIN_8 ||
	    td->mtclass.name == MT_CLS_WIN_8_FORCE_MULTI_INPUT)) {
		if (hid_haptic_input_configured(hdev, td->haptic, hi) == 0)
			td->is_haptic_touchpad = false;
	} else {
		td->is_haptic_touchpad = false;
	}

	list_for_each_entry(report, &hi->reports, hidinput_list) {
		rdata = mt_find_report_data(td, report);
		if (!rdata) {
@@ -1827,6 +1858,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
		dev_err(&hdev->dev, "cannot allocate multitouch data\n");
		return -ENOMEM;
	}
	td->haptic = devm_kzalloc(&hdev->dev, sizeof(*(td->haptic)), GFP_KERNEL);
	if (!td->haptic)
		return -ENOMEM;

	td->haptic->hdev = hdev;
	td->hdev = hdev;
	td->mtclass = *mtclass;
	td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
@@ -1895,6 +1931,17 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)

	mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_ALL);

	if (td->is_haptic_touchpad) {
		if (hid_haptic_init(hdev, &td->haptic)) {
			dev_warn(&hdev->dev, "Cannot allocate haptic for %s\n",
				 hdev->name);
			td->is_haptic_touchpad = false;
			devm_kfree(&hdev->dev, td->haptic);
		}
	} else {
		devm_kfree(&hdev->dev, td->haptic);
	}

	return 0;
}