diff mbox series

[v4,09/17] HID: haptic: add functions handling events

Message ID 20221007182945.1654046-10-acz@semihalf.com
State New
Headers show
Series *** Implement simple haptic HID support *** | expand

Commit Message

Angela Czubak Oct. 7, 2022, 6:29 p.m. UTC
Implement hid_haptic_handle_press_release() which generates haptic feedback
as well as saves the pressed state of the haptic device.
Function hid_haptic_handle_input() inserts BTN_LEFT and ABS_PRESSURE events
if the device is in kernel mode.
Add functions to increase and reset the state of the pressure detected by
the device.

Signed-off-by: Angela Czubak <acz@semihalf.com>
---
 drivers/hid/hid-haptic.c | 73 +++++++++++++++++++++++++++++++++++++++-
 drivers/hid/hid-haptic.h | 18 ++++++++++
 2 files changed, 90 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/hid/hid-haptic.c b/drivers/hid/hid-haptic.c
index 3301bf27dfdee..9b89a1f8a6316 100644
--- a/drivers/hid/hid-haptic.c
+++ b/drivers/hid/hid-haptic.c
@@ -50,8 +50,13 @@  EXPORT_SYMBOL_GPL(hid_haptic_feature_mapping);
 bool hid_haptic_is_forcepad(struct hid_haptic_device *haptic,
 			    struct hid_input *hi, struct hid_field *field)
 {
-	if (field->unit == HID_UNIT_GRAM || field->unit == HID_UNIT_NEWTON)
+	if (field->unit == HID_UNIT_GRAM || field->unit == HID_UNIT_NEWTON) {
+		haptic->force_logical_minimum = field->logical_minimum;
+		haptic->force_physical_minimum = field->physical_minimum;
+		haptic->force_resolution = input_abs_get_res(hi->input,
+							     ABS_MT_PRESSURE);
 		haptic->is_forcepad = true;
+	}
 	return haptic->is_forcepad;
 }
 EXPORT_SYMBOL_GPL(hid_haptic_is_forcepad);
@@ -346,6 +351,12 @@  static void hid_haptic_destroy(struct ff_device *ff)
 	module_put(THIS_MODULE);
 }
 
+static u32 convert_force_to_logical(struct hid_haptic_device *haptic, u32 value)
+{
+	return (value - haptic->force_physical_minimum) *
+		haptic->force_resolution + haptic->force_logical_minimum;
+}
+
 int hid_haptic_init(struct hid_device *hdev,
 		    struct hid_haptic_device **haptic_ptr)
 {
@@ -479,9 +490,16 @@  int hid_haptic_init(struct hid_device *hdev,
 		goto input_free;
 	}
 
+	haptic->mode = HID_HAPTIC_MODE_DEVICE;
+
 	if (!haptic->is_forcepad)
 		goto exit;
 
+	haptic->press_threshold = convert_force_to_logical(haptic,
+							   HID_HAPTIC_PRESS_THRESH);
+	haptic->release_threshold = convert_force_to_logical(haptic,
+							     HID_HAPTIC_RELEASE_THRESH);
+
 	effect_set_default(&release_effect);
 	if (haptic->release_ordinal_orig)
 		release_effect.u.hid.hid_usage = HID_HP_WAVEFORMRELEASE &
@@ -547,3 +565,56 @@  int hid_haptic_init(struct hid_device *hdev,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(hid_haptic_init);
+
+void hid_haptic_handle_press_release(struct hid_haptic_device *haptic)
+{
+	int prev_pressed_state = haptic->pressed_state;
+	struct input_dev *input = haptic->input_dev;
+	unsigned long flags;
+
+	if (!haptic->is_forcepad)
+		return;
+
+	if (haptic->pressure > haptic->press_threshold)
+		haptic->pressed_state = 1;
+	else if (haptic->pressure < haptic->release_threshold)
+		haptic->pressed_state = 0;
+	if (!prev_pressed_state && haptic->pressed_state &&
+	    haptic->mode == HID_HAPTIC_MODE_KERNEL) {
+		spin_lock_irqsave(&input->event_lock, flags);
+		input->ff->playback(input, PRESS_HID_EFFECT_ID, 1);
+		spin_unlock_irqrestore(&input->event_lock, flags);
+	}
+	if (prev_pressed_state && !haptic->pressed_state &&
+	    haptic->mode == HID_HAPTIC_MODE_KERNEL) {
+		spin_lock_irqsave(&input->event_lock, flags);
+		input->ff->playback(input, RELEASE_HID_EFFECT_ID, 1);
+		spin_unlock_irqrestore(&input->event_lock, flags);
+	}
+}
+EXPORT_SYMBOL_GPL(hid_haptic_handle_press_release);
+
+bool hid_haptic_handle_input(struct hid_haptic_device *haptic)
+{
+	if (haptic->is_forcepad && haptic->mode == HID_HAPTIC_MODE_KERNEL) {
+		input_event(haptic->input_dev, EV_KEY, BTN_LEFT,
+			    haptic->pressed_state);
+		return true;
+	}
+	return false;
+}
+EXPORT_SYMBOL_GPL(hid_haptic_handle_input);
+
+void hid_haptic_pressure_reset(struct hid_haptic_device *haptic)
+{
+	haptic->pressure = 0;
+}
+EXPORT_SYMBOL_GPL(hid_haptic_pressure_reset);
+
+void hid_haptic_pressure_update(struct hid_haptic_device *haptic,
+				__s32 pressure)
+{
+	if (pressure > haptic->pressure)
+		haptic->pressure = pressure;
+}
+EXPORT_SYMBOL_GPL(hid_haptic_pressure_update);
diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h
index 67096cc8c2331..c26093e3773d1 100644
--- a/drivers/hid/hid-haptic.h
+++ b/drivers/hid/hid-haptic.h
@@ -83,6 +83,11 @@  int hid_haptic_input_mapping(struct hid_device *hdev,
 bool hid_haptic_input_configured(struct hid_device *hdev,
 				 struct hid_haptic_device *haptic);
 int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_ptr);
+void hid_haptic_handle_press_release(struct hid_haptic_device *haptic);
+bool hid_haptic_handle_input(struct hid_haptic_device *haptic);
+void hid_haptic_pressure_reset(struct hid_haptic_device *haptic);
+void hid_haptic_pressure_update(struct hid_haptic_device *haptic,
+				__s32 pressure);
 #else
 static inline
 void hid_haptic_feature_mapping(struct hid_device *hdev,
@@ -116,4 +121,17 @@  int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device **haptic_p
 {
 	return 0;
 }
+static inline
+void hid_haptic_handle_press_release(struct hid_haptic_device *haptic) {}
+static inline
+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_update(struct hid_haptic_device *haptic,
+				  __s32 pressure)
+{}
 #endif