mirror of https://github.com/torvalds/linux.git
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: Angela Czubak <aczubak@google.com> Co-developed-by: Jonathan Denose <jdenose@google.com> Signed-off-by: Jonathan Denose <jdenose@google.com> Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
This commit is contained in:
parent
ff66b8eebb
commit
8d0bf7908b
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue