diff --git a/drivers/hid/hid-haptic.c b/drivers/hid/hid-haptic.c
index 9817d661f93d..84985ad61d45 100644
--- a/drivers/hid/hid-haptic.c
+++ b/drivers/hid/hid-haptic.c
@@ -48,17 +48,40 @@ void hid_haptic_feature_mapping(struct hid_device *hdev,
}
EXPORT_SYMBOL_GPL(hid_haptic_feature_mapping);
-bool hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic,
+void hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic,
struct hid_input *hi, struct hid_field *field)
{
- 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);
- return true;
+ if (hi->application != HID_DG_TOUCHPAD)
+ return;
+
+ if (IS_ERR(haptic->input_dev))
+ return;
+
+ if (field->unit != HID_UNIT_GRAM && field->unit != HID_UNIT_NEWTON)
+ goto reject;
+
+ if (!haptic->input_dev) {
+ haptic->input_dev = hi->input;
+ haptic->pressure_field = field;
+ haptic->force_resolution = input_abs_get_res(hi->input, ABS_MT_PRESSURE);
+ return;
}
- return false;
+
+ if (hid_haptic_connected_to_input(haptic, hi->input) &&
+ haptic->pressure_field->unit == field->unit &&
+ haptic->pressure_field->logical_minimum == field->logical_minimum &&
+ haptic->pressure_field->physical_minimum == field->physical_minimum &&
+ haptic->force_resolution == input_abs_get_res(hi->input, ABS_MT_PRESSURE))
+ return;
+
+reject:
+ /*
+ * Reject if:
+ * - there are multiple input devices with pressure sensors
+ * - there is any touchpad application with a non-force unit
+ * - pressure annotations mismatch among HID_DG_TIPPRESSURE usages
+ */
+ haptic->input_dev = ERR_PTR(-EPROTO);
}
EXPORT_SYMBOL_GPL(hid_haptic_check_pressure_unit);
@@ -78,28 +101,16 @@ int hid_haptic_input_mapping(struct hid_device *hdev,
}
EXPORT_SYMBOL_GPL(hid_haptic_input_mapping);
-int hid_haptic_input_configured(struct hid_device *hdev,
- struct hid_haptic_device *haptic,
- struct hid_input *hi)
+bool hid_haptic_input_configured(struct hid_device *hdev,
+ struct hid_haptic_device *haptic, struct hid_input *hi)
{
- int error;
-
- if (hi->application != HID_DG_TOUCHPAD)
- return -1;
-
- if (!haptic->auto_trigger_report || !haptic->manual_trigger_report)
- return 0;
+ if (IS_ERR_OR_NULL(haptic->input_dev) || haptic->input_dev != hi->input ||
+ !haptic->auto_trigger_report || !haptic->manual_trigger_report)
+ return false;
__set_bit(INPUT_PROP_PRESSUREPAD, hi->input->propbit);
- error = hid_haptic_init(hdev, haptic, hi->input);
- if (error) {
- dev_warn(&hdev->dev, "Cannot allocate haptic for %s\n",
- hdev->name);
- return 0;
- }
-
- return 1;
+ return hid_haptic_init(hdev, haptic, hi->input) == 0;
}
EXPORT_SYMBOL_GPL(hid_haptic_input_configured);
@@ -537,6 +548,7 @@ int hid_haptic_init(struct hid_device *hdev,
put_device:
put_device(&hdev->dev);
exit:
+ dev_warn(&hdev->dev, "Cannot allocate haptic for %s: %d\n", hdev->name, ret);
module_put(THIS_MODULE);
return ret;
}
diff --git a/drivers/hid/hid-haptic.h b/drivers/hid/hid-haptic.h
index 6332991a7844..cd4d9c74d2dc 100644
--- a/drivers/hid/hid-haptic.h
+++ b/drivers/hid/hid-haptic.h
@@ -33,12 +33,11 @@ struct hid_haptic_device {
struct mutex auto_trigger_mutex;
struct workqueue_struct *wq;
struct hid_report *manual_trigger_report;
+ struct hid_field *pressure_field;
struct mutex manual_trigger_mutex;
size_t manual_trigger_report_len;
int pressed_state;
s32 pressure_sum;
- s32 force_logical_minimum;
- s32 force_physical_minimum;
s32 force_resolution;
u32 mode;
u32 default_auto_trigger;@@ -55,20 +54,25 @@ struct hid_haptic_device {
};
#if IS_ENABLED(CONFIG_HID_HAPTIC)
+static inline bool hid_haptic_connected_to_input(struct hid_haptic_device *haptic,
+ struct input_dev *input)
+{
+ return haptic->input_dev == input;
+}
+
void hid_haptic_feature_mapping(struct hid_device *hdev,
struct hid_haptic_device *haptic,
struct hid_field *field, struct hid_usage
*usage);
-bool hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic,
+void hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic,
struct hid_input *hi, struct hid_field *field);
int hid_haptic_input_mapping(struct hid_device *hdev,
struct hid_haptic_device *haptic,
struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max);
-int hid_haptic_input_configured(struct hid_device *hdev,
- struct hid_haptic_device *haptic,
- struct hid_input *hi);
+bool hid_haptic_input_configured(struct hid_device *hdev,
+ struct hid_haptic_device *haptic, struct hid_input *hi);
int hid_haptic_init(struct hid_device *hdev, struct hid_haptic_device *haptic,
struct input_dev *dev);
void hid_haptic_handle_press_release(struct hid_haptic_device *haptic);@@ -76,6 +80,12 @@ void hid_haptic_pressure_reset(struct hid_haptic_device *haptic);
void hid_haptic_pressure_increase(struct hid_haptic_device *haptic,
__s32 pressure);
#else
+static inline bool hid_haptic_connected_to_input(struct hid_haptic_device *haptic,
+ struct input_dev *input)
+{
+ return false;
+}
+
static inline
void hid_haptic_feature_mapping(struct hid_device *hdev,
struct hid_haptic_device *haptic,@@ -83,11 +93,9 @@ void hid_haptic_feature_mapping(struct hid_device *hdev,
*usage)
{}
static inline
-bool hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic,
+void hid_haptic_check_pressure_unit(struct hid_haptic_device *haptic,
struct hid_input *hi, struct hid_field *field)
-{
- return false;
-}
+{}
static inline
int hid_haptic_input_mapping(struct hid_device *hdev,
struct hid_haptic_device *haptic,@@ -98,11 +106,10 @@ int hid_haptic_input_mapping(struct hid_device *hdev,
return 0;
}
static inline
-int hid_haptic_input_configured(struct hid_device *hdev,
- struct hid_haptic_device *haptic,
- struct hid_input *hi)
+bool hid_haptic_input_configured(struct hid_device *hdev,
+ struct hid_haptic_device *haptic, struct hid_input *hi)
{
- return 0;
+ return false;
}
static inline
void hid_haptic_reset(struct hid_device *hdev, struct hid_haptic_device *haptic)diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 3afca07025ea..5eea774dee44 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -605,7 +605,8 @@ static void mt_feature_mapping(struct hid_device *hdev,
break;
}
- hid_haptic_feature_mapping(hdev, td->haptic, field, usage);
+ if (td->haptic)
+ hid_haptic_feature_mapping(hdev, td->haptic, field, usage);
}
static void set_abs(struct input_dev *input, unsigned int code,
@@ -961,9 +962,8 @@ 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);
+ if (td->haptic)
+ hid_haptic_check_pressure_unit(td->haptic, hi, field);
MT_STORE_FIELD(p);
return 1;
case HID_DG_SCANTIME:
@@ -1085,7 +1085,7 @@ 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)
+ if (td->is_haptic_touchpad && hid_haptic_connected_to_input(td->haptic, input))
hid_haptic_pressure_reset(td->haptic);
}
@@ -1238,7 +1238,7 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
minor = minor >> 1;
}
- if (td->is_haptic_touchpad)
+ if (td->is_haptic_touchpad && hid_haptic_connected_to_input(td->haptic, input))
hid_haptic_pressure_increase(td->haptic, *slot->p);
x = hdev->quirks & HID_QUIRK_X_INVERT ?
@@ -1441,7 +1441,7 @@ 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)
+ if (td->is_haptic_touchpad && hid_haptic_connected_to_input(td->haptic, input))
app->mt_flags |= INPUT_MT_TOTAL_FORCE;
if (app->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
@@ -1553,10 +1553,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;
+ if (td->haptic) {
+ ret = hid_haptic_input_mapping(hdev, td->haptic, hi, field, usage, bit, max);
+ if (ret)
+ return ret;
+ }
/* let hid-core decide for the others */
return 0;@@ -1954,14 +1955,11 @@ 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 ||
- td->mtclass.name == MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE)) {
- if (hid_haptic_input_configured(hdev, td->haptic, hi) == 0)
- td->is_haptic_touchpad = false;
- } else {
- td->is_haptic_touchpad = false;
- }
+ if (td->haptic && !td->is_haptic_touchpad &&
+ (td->mtclass.name == MT_CLS_WIN_8 ||
+ td->mtclass.name == MT_CLS_WIN_8_FORCE_MULTI_INPUT ||
+ td->mtclass.name == MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE))
+ td->is_haptic_touchpad = hid_haptic_input_configured(hdev, td->haptic, hi);
list_for_each_entry(report, &hi->reports, hidinput_list) {
rdata = mt_find_report_data(td, report);
--
2.55.0