HID: multitouch: remove one copy of values
The current way of handling multitouch data is not very straightforward: - in mt_event() we do nothing - in mt_report() we: - do some gym to fetch the scantime and the contact count - then iterate over the input fields where we copy the data to a temporary place - when we see the last field in a slot, we then use this data to emit the input data A more streamlined way is to first get all of the address in the report of all fields, and then just pick the fields we are interested in in mt_report() Acked-by: Peter Hutterer <peter.hutterer@who-t.net> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
This commit is contained in:
parent
8dfe14b3b4
commit
01eaac7e57
|
@ -87,30 +87,34 @@ enum latency_mode {
|
||||||
#define MT_IO_FLAGS_ACTIVE_SLOTS 1
|
#define MT_IO_FLAGS_ACTIVE_SLOTS 1
|
||||||
#define MT_IO_FLAGS_PENDING_SLOTS 2
|
#define MT_IO_FLAGS_PENDING_SLOTS 2
|
||||||
|
|
||||||
struct mt_slot {
|
static const bool mtrue = true; /* default for true */
|
||||||
__s32 x, y, cx, cy, p, w, h, a;
|
static const bool mfalse; /* default for false */
|
||||||
__s32 contactid; /* the device ContactID assigned to this slot */
|
static const __s32 mzero; /* default for 0 */
|
||||||
bool touch_state; /* is the touch valid? */
|
|
||||||
bool inrange_state; /* is the finger in proximity of the sensor? */
|
#define DEFAULT_TRUE ((void *)&mtrue)
|
||||||
bool confidence_state; /* is the touch made by a finger? */
|
#define DEFAULT_FALSE ((void *)&mfalse)
|
||||||
bool has_azimuth; /* the contact reports azimuth */
|
#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 mt_application {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
unsigned int application;
|
unsigned int application;
|
||||||
|
struct list_head mt_usages; /* mt usages list */
|
||||||
|
|
||||||
__s32 quirks;
|
__s32 quirks;
|
||||||
|
|
||||||
struct mt_slot curdata; /* placeholder of incoming data */
|
__s32 *scantime; /* scantime reported */
|
||||||
|
__s32 scantime_logical_max; /* max value for raw scantime */
|
||||||
int cc_index; /* contact count field index in the report */
|
|
||||||
int cc_value_index; /* contact count value index in the field */
|
|
||||||
int scantime_index; /* scantime field index in the report */
|
|
||||||
int scantime_val_index; /* scantime value index in the field */
|
|
||||||
unsigned int last_slot_field; /* the last field of a slot */
|
|
||||||
bool curvalid; /* is the current contact valid? */
|
|
||||||
|
|
||||||
|
__s32 *raw_cc; /* contact count in the report */
|
||||||
int left_button_state; /* left button state */
|
int left_button_state; /* left button state */
|
||||||
unsigned int mt_flags; /* flags to pass to input-mt */
|
unsigned int mt_flags; /* flags to pass to input-mt */
|
||||||
|
|
||||||
|
@ -142,11 +146,6 @@ struct mt_class {
|
||||||
bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */
|
bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mt_fields {
|
|
||||||
unsigned usages[HID_MAX_FIELDS];
|
|
||||||
unsigned int length;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mt_report_data {
|
struct mt_report_data {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct hid_report *report;
|
struct hid_report *report;
|
||||||
|
@ -158,8 +157,6 @@ struct mt_device {
|
||||||
struct mt_class mtclass; /* our mt device class */
|
struct mt_class mtclass; /* our mt device class */
|
||||||
struct timer_list release_timer; /* to release sticky fingers */
|
struct timer_list release_timer; /* to release sticky fingers */
|
||||||
struct hid_device *hdev; /* hid_device we're attached to */
|
struct hid_device *hdev; /* hid_device we're attached to */
|
||||||
struct mt_fields *fields; /* temporary placeholder for storing the
|
|
||||||
multitouch fields */
|
|
||||||
unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */
|
unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */
|
||||||
__u8 inputmode_value; /* InputMode HID feature value */
|
__u8 inputmode_value; /* InputMode HID feature value */
|
||||||
__u8 maxcontacts;
|
__u8 maxcontacts;
|
||||||
|
@ -225,10 +222,11 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
|
||||||
* to a valid contact that was just read.
|
* to a valid contact that was just read.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int cypress_compute_slot(struct mt_application *app)
|
static int cypress_compute_slot(struct mt_application *application,
|
||||||
|
struct mt_usages *slot)
|
||||||
{
|
{
|
||||||
if (app->curdata.contactid != 0 || app->num_received == 0)
|
if (*slot->contactid != 0 || application->num_received == 0)
|
||||||
return app->curdata.contactid;
|
return *slot->contactid;
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -483,6 +481,34 @@ static void set_abs(struct input_dev *input, unsigned int code,
|
||||||
input_abs_set_res(input, code, hidinput_calc_abs_res(field, code));
|
input_abs_set_res(input, code, hidinput_calc_abs_res(field, code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct mt_usages *mt_allocate_usage(struct hid_device *hdev,
|
||||||
|
struct mt_application *application)
|
||||||
|
{
|
||||||
|
struct mt_usages *usage;
|
||||||
|
|
||||||
|
usage = devm_kzalloc(&hdev->dev, sizeof(*usage), GFP_KERNEL);
|
||||||
|
if (!usage)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* set some defaults so we do not need to check for null pointers */
|
||||||
|
usage->x = DEFAULT_ZERO;
|
||||||
|
usage->y = DEFAULT_ZERO;
|
||||||
|
usage->cx = DEFAULT_ZERO;
|
||||||
|
usage->cy = DEFAULT_ZERO;
|
||||||
|
usage->p = DEFAULT_ZERO;
|
||||||
|
usage->w = DEFAULT_ZERO;
|
||||||
|
usage->h = DEFAULT_ZERO;
|
||||||
|
usage->a = DEFAULT_ZERO;
|
||||||
|
usage->contactid = DEFAULT_ZERO;
|
||||||
|
usage->tip_state = DEFAULT_FALSE;
|
||||||
|
usage->inrange_state = DEFAULT_FALSE;
|
||||||
|
usage->confidence_state = DEFAULT_TRUE;
|
||||||
|
|
||||||
|
list_add_tail(&usage->list, &application->mt_usages);
|
||||||
|
|
||||||
|
return usage;
|
||||||
|
}
|
||||||
|
|
||||||
static struct mt_application *mt_allocate_application(struct mt_device *td,
|
static struct mt_application *mt_allocate_application(struct mt_device *td,
|
||||||
unsigned int application)
|
unsigned int application)
|
||||||
{
|
{
|
||||||
|
@ -494,6 +520,7 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
mt_application->application = application;
|
mt_application->application = application;
|
||||||
|
INIT_LIST_HEAD(&mt_application->mt_usages);
|
||||||
|
|
||||||
if (application == HID_DG_TOUCHSCREEN)
|
if (application == HID_DG_TOUCHSCREEN)
|
||||||
mt_application->mt_flags |= INPUT_MT_DIRECT;
|
mt_application->mt_flags |= INPUT_MT_DIRECT;
|
||||||
|
@ -506,8 +533,8 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
|
||||||
td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
|
td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
mt_application->cc_index = -1;
|
mt_application->scantime = DEFAULT_ZERO;
|
||||||
mt_application->scantime_index = -1;
|
mt_application->raw_cc = DEFAULT_ZERO;
|
||||||
mt_application->quirks = td->mtclass.quirks;
|
mt_application->quirks = td->mtclass.quirks;
|
||||||
|
|
||||||
list_add_tail(&mt_application->list, &td->applications);
|
list_add_tail(&mt_application->list, &td->applications);
|
||||||
|
@ -587,17 +614,45 @@ static struct mt_report_data *mt_find_report_data(struct mt_device *td,
|
||||||
return rdata;
|
return rdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
|
static void mt_store_field(struct hid_device *hdev,
|
||||||
struct hid_input *hi)
|
struct mt_application *application,
|
||||||
|
__s32 *value,
|
||||||
|
size_t offset)
|
||||||
{
|
{
|
||||||
struct mt_fields *f = td->fields;
|
struct mt_usages *usage;
|
||||||
|
__s32 **target;
|
||||||
|
|
||||||
if (f->length >= HID_MAX_FIELDS)
|
if (list_empty(&application->mt_usages))
|
||||||
|
usage = mt_allocate_usage(hdev, application);
|
||||||
|
else
|
||||||
|
usage = list_last_entry(&application->mt_usages,
|
||||||
|
struct mt_usages,
|
||||||
|
list);
|
||||||
|
|
||||||
|
if (!usage)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
f->usages[f->length++] = usage->hid;
|
target = (__s32 **)((char *)usage + offset);
|
||||||
|
|
||||||
|
/* the value has already been filled, create a new slot */
|
||||||
|
if (*target != DEFAULT_TRUE &&
|
||||||
|
*target != DEFAULT_FALSE &&
|
||||||
|
*target != DEFAULT_ZERO) {
|
||||||
|
usage = mt_allocate_usage(hdev, application);
|
||||||
|
if (!usage)
|
||||||
|
return;
|
||||||
|
|
||||||
|
target = (__s32 **)((char *)usage + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
*target = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MT_STORE_FIELD(__name) \
|
||||||
|
mt_store_field(hdev, app, \
|
||||||
|
&field->value[usage->usage_index], \
|
||||||
|
offsetof(struct mt_usages, __name))
|
||||||
|
|
||||||
static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||||
struct hid_field *field, struct hid_usage *usage,
|
struct hid_field *field, struct hid_usage *usage,
|
||||||
unsigned long **bit, int *max, struct mt_application *app)
|
unsigned long **bit, int *max, struct mt_application *app)
|
||||||
|
@ -627,24 +682,28 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||||
case HID_UP_GENDESK:
|
case HID_UP_GENDESK:
|
||||||
switch (usage->hid) {
|
switch (usage->hid) {
|
||||||
case HID_GD_X:
|
case HID_GD_X:
|
||||||
if (prev_usage && (prev_usage->hid == usage->hid))
|
if (prev_usage && (prev_usage->hid == usage->hid)) {
|
||||||
code = ABS_MT_TOOL_X;
|
code = ABS_MT_TOOL_X;
|
||||||
else
|
MT_STORE_FIELD(cx);
|
||||||
|
} else {
|
||||||
code = ABS_MT_POSITION_X;
|
code = ABS_MT_POSITION_X;
|
||||||
|
MT_STORE_FIELD(x);
|
||||||
|
}
|
||||||
|
|
||||||
hid_map_usage(hi, usage, bit, max, EV_ABS, code);
|
|
||||||
set_abs(hi->input, code, field, cls->sn_move);
|
set_abs(hi->input, code, field, cls->sn_move);
|
||||||
mt_store_field(usage, td, hi);
|
|
||||||
return 1;
|
return 1;
|
||||||
case HID_GD_Y:
|
case HID_GD_Y:
|
||||||
if (prev_usage && (prev_usage->hid == usage->hid))
|
if (prev_usage && (prev_usage->hid == usage->hid)) {
|
||||||
code = ABS_MT_TOOL_Y;
|
code = ABS_MT_TOOL_Y;
|
||||||
else
|
MT_STORE_FIELD(cy);
|
||||||
|
} else {
|
||||||
code = ABS_MT_POSITION_Y;
|
code = ABS_MT_POSITION_Y;
|
||||||
|
MT_STORE_FIELD(y);
|
||||||
|
}
|
||||||
|
|
||||||
hid_map_usage(hi, usage, bit, max, EV_ABS, code);
|
|
||||||
set_abs(hi->input, code, field, cls->sn_move);
|
set_abs(hi->input, code, field, cls->sn_move);
|
||||||
mt_store_field(usage, td, hi);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -653,40 +712,33 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||||
switch (usage->hid) {
|
switch (usage->hid) {
|
||||||
case HID_DG_INRANGE:
|
case HID_DG_INRANGE:
|
||||||
if (app->quirks & MT_QUIRK_HOVERING) {
|
if (app->quirks & MT_QUIRK_HOVERING) {
|
||||||
hid_map_usage(hi, usage, bit, max,
|
|
||||||
EV_ABS, ABS_MT_DISTANCE);
|
|
||||||
input_set_abs_params(hi->input,
|
input_set_abs_params(hi->input,
|
||||||
ABS_MT_DISTANCE, 0, 1, 0, 0);
|
ABS_MT_DISTANCE, 0, 1, 0, 0);
|
||||||
}
|
}
|
||||||
mt_store_field(usage, td, hi);
|
MT_STORE_FIELD(inrange_state);
|
||||||
return 1;
|
return 1;
|
||||||
case HID_DG_CONFIDENCE:
|
case HID_DG_CONFIDENCE:
|
||||||
if ((cls->name == MT_CLS_WIN_8 ||
|
if ((cls->name == MT_CLS_WIN_8 ||
|
||||||
cls->name == MT_CLS_WIN_8_DUAL) &&
|
cls->name == MT_CLS_WIN_8_DUAL) &&
|
||||||
field->application == HID_DG_TOUCHPAD)
|
field->application == HID_DG_TOUCHPAD)
|
||||||
app->quirks |= MT_QUIRK_CONFIDENCE;
|
app->quirks |= MT_QUIRK_CONFIDENCE;
|
||||||
mt_store_field(usage, td, hi);
|
MT_STORE_FIELD(confidence_state);
|
||||||
return 1;
|
return 1;
|
||||||
case HID_DG_TIPSWITCH:
|
case HID_DG_TIPSWITCH:
|
||||||
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
|
|
||||||
input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
|
input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
|
||||||
mt_store_field(usage, td, hi);
|
MT_STORE_FIELD(tip_state);
|
||||||
return 1;
|
return 1;
|
||||||
case HID_DG_CONTACTID:
|
case HID_DG_CONTACTID:
|
||||||
mt_store_field(usage, td, hi);
|
MT_STORE_FIELD(contactid);
|
||||||
app->touches_by_report++;
|
app->touches_by_report++;
|
||||||
return 1;
|
return 1;
|
||||||
case HID_DG_WIDTH:
|
case HID_DG_WIDTH:
|
||||||
hid_map_usage(hi, usage, bit, max,
|
|
||||||
EV_ABS, ABS_MT_TOUCH_MAJOR);
|
|
||||||
if (!(app->quirks & MT_QUIRK_NO_AREA))
|
if (!(app->quirks & MT_QUIRK_NO_AREA))
|
||||||
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
|
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
|
||||||
cls->sn_width);
|
cls->sn_width);
|
||||||
mt_store_field(usage, td, hi);
|
MT_STORE_FIELD(w);
|
||||||
return 1;
|
return 1;
|
||||||
case HID_DG_HEIGHT:
|
case HID_DG_HEIGHT:
|
||||||
hid_map_usage(hi, usage, bit, max,
|
|
||||||
EV_ABS, ABS_MT_TOUCH_MINOR);
|
|
||||||
if (!(app->quirks & MT_QUIRK_NO_AREA)) {
|
if (!(app->quirks & MT_QUIRK_NO_AREA)) {
|
||||||
set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
|
set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
|
||||||
cls->sn_height);
|
cls->sn_height);
|
||||||
|
@ -700,37 +752,23 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||||
input_set_abs_params(hi->input,
|
input_set_abs_params(hi->input,
|
||||||
ABS_MT_ORIENTATION, 0, 1, 0, 0);
|
ABS_MT_ORIENTATION, 0, 1, 0, 0);
|
||||||
}
|
}
|
||||||
mt_store_field(usage, td, hi);
|
MT_STORE_FIELD(h);
|
||||||
return 1;
|
return 1;
|
||||||
case HID_DG_TIPPRESSURE:
|
case HID_DG_TIPPRESSURE:
|
||||||
hid_map_usage(hi, usage, bit, max,
|
|
||||||
EV_ABS, ABS_MT_PRESSURE);
|
|
||||||
set_abs(hi->input, ABS_MT_PRESSURE, field,
|
set_abs(hi->input, ABS_MT_PRESSURE, field,
|
||||||
cls->sn_pressure);
|
cls->sn_pressure);
|
||||||
mt_store_field(usage, td, hi);
|
MT_STORE_FIELD(p);
|
||||||
return 1;
|
return 1;
|
||||||
case HID_DG_SCANTIME:
|
case HID_DG_SCANTIME:
|
||||||
hid_map_usage(hi, usage, bit, max,
|
|
||||||
EV_MSC, MSC_TIMESTAMP);
|
|
||||||
input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP);
|
input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP);
|
||||||
/* Ignore if indexes are out of bounds. */
|
app->scantime = &field->value[usage->usage_index];
|
||||||
if (field->index >= field->report->maxfield ||
|
app->scantime_logical_max = field->logical_maximum;
|
||||||
usage->usage_index >= field->report_count)
|
|
||||||
return 1;
|
|
||||||
app->scantime_index = field->index;
|
|
||||||
app->scantime_val_index = usage->usage_index;
|
|
||||||
return 1;
|
return 1;
|
||||||
case HID_DG_CONTACTCOUNT:
|
case HID_DG_CONTACTCOUNT:
|
||||||
/* Ignore if indexes are out of bounds. */
|
app->have_contact_count = true;
|
||||||
if (field->index >= field->report->maxfield ||
|
app->raw_cc = &field->value[usage->usage_index];
|
||||||
usage->usage_index >= field->report_count)
|
|
||||||
return 1;
|
|
||||||
app->cc_index = field->index;
|
|
||||||
app->cc_value_index = usage->usage_index;
|
|
||||||
return 1;
|
return 1;
|
||||||
case HID_DG_AZIMUTH:
|
case HID_DG_AZIMUTH:
|
||||||
hid_map_usage(hi, usage, bit, max,
|
|
||||||
EV_ABS, ABS_MT_ORIENTATION);
|
|
||||||
/*
|
/*
|
||||||
* Azimuth has the range of [0, MAX) representing a full
|
* Azimuth has the range of [0, MAX) representing a full
|
||||||
* revolution. Set ABS_MT_ORIENTATION to a quarter of
|
* revolution. Set ABS_MT_ORIENTATION to a quarter of
|
||||||
|
@ -741,11 +779,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||||
field->logical_maximum / 4,
|
field->logical_maximum / 4,
|
||||||
cls->sn_move ?
|
cls->sn_move ?
|
||||||
field->logical_maximum / cls->sn_move : 0, 0);
|
field->logical_maximum / cls->sn_move : 0, 0);
|
||||||
mt_store_field(usage, td, hi);
|
MT_STORE_FIELD(a);
|
||||||
return 1;
|
return 1;
|
||||||
case HID_DG_CONTACTMAX:
|
case HID_DG_CONTACTMAX:
|
||||||
/* we don't set td->last_slot_field as contactcount and
|
/* contact max are global to the report */
|
||||||
* contact max are global to the report */
|
|
||||||
return -1;
|
return -1;
|
||||||
case HID_DG_TOUCH:
|
case HID_DG_TOUCH:
|
||||||
/* Legacy devices use TIPSWITCH and not TOUCH.
|
/* Legacy devices use TIPSWITCH and not TOUCH.
|
||||||
|
@ -778,95 +815,24 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
|
static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
|
||||||
|
struct mt_usages *slot,
|
||||||
struct input_dev *input)
|
struct input_dev *input)
|
||||||
{
|
{
|
||||||
__s32 quirks = app->quirks;
|
__s32 quirks = app->quirks;
|
||||||
|
|
||||||
if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
|
if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
|
||||||
return app->curdata.contactid;
|
return *slot->contactid;
|
||||||
|
|
||||||
if (quirks & MT_QUIRK_CYPRESS)
|
if (quirks & MT_QUIRK_CYPRESS)
|
||||||
return cypress_compute_slot(app);
|
return cypress_compute_slot(app, slot);
|
||||||
|
|
||||||
if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
|
if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
|
||||||
return app->num_received;
|
return app->num_received;
|
||||||
|
|
||||||
if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
|
if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
|
||||||
return app->curdata.contactid - 1;
|
return *slot->contactid - 1;
|
||||||
|
|
||||||
return input_mt_get_slot_by_key(input, app->curdata.contactid);
|
return input_mt_get_slot_by_key(input, *slot->contactid);
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* this function is called when a whole contact has been processed,
|
|
||||||
* so that it can assign it to a slot and store the data there
|
|
||||||
*/
|
|
||||||
static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
|
|
||||||
struct input_dev *input)
|
|
||||||
{
|
|
||||||
if ((app->quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
|
|
||||||
app->num_received >= app->num_expected)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (app->curvalid || (app->quirks & MT_QUIRK_ALWAYS_VALID)) {
|
|
||||||
int active;
|
|
||||||
int slotnum = mt_compute_slot(td, app, input);
|
|
||||||
struct mt_slot *s = &app->curdata;
|
|
||||||
struct input_mt *mt = input->mt;
|
|
||||||
|
|
||||||
if (slotnum < 0 || slotnum >= td->maxcontacts)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ((app->quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) {
|
|
||||||
struct input_mt_slot *slot = &mt->slots[slotnum];
|
|
||||||
if (input_mt_is_active(slot) &&
|
|
||||||
input_mt_is_used(mt, slot))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(app->quirks & MT_QUIRK_CONFIDENCE))
|
|
||||||
s->confidence_state = true;
|
|
||||||
active = (s->touch_state || s->inrange_state) &&
|
|
||||||
s->confidence_state;
|
|
||||||
|
|
||||||
input_mt_slot(input, slotnum);
|
|
||||||
input_mt_report_slot_state(input, MT_TOOL_FINGER, active);
|
|
||||||
if (active) {
|
|
||||||
/* this finger is in proximity of the sensor */
|
|
||||||
int wide = (s->w > s->h);
|
|
||||||
int major = max(s->w, s->h);
|
|
||||||
int minor = min(s->w, s->h);
|
|
||||||
int orientation = wide;
|
|
||||||
|
|
||||||
if (s->has_azimuth)
|
|
||||||
orientation = s->a;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* divided by two to match visual scale of touch
|
|
||||||
* for devices with this quirk
|
|
||||||
*/
|
|
||||||
if (app->quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
|
|
||||||
major = major >> 1;
|
|
||||||
minor = minor >> 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);
|
|
||||||
input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);
|
|
||||||
input_event(input, EV_ABS, ABS_MT_TOOL_X, s->cx);
|
|
||||||
input_event(input, EV_ABS, ABS_MT_TOOL_Y, s->cy);
|
|
||||||
input_event(input, EV_ABS, ABS_MT_DISTANCE,
|
|
||||||
!s->touch_state);
|
|
||||||
input_event(input, EV_ABS, ABS_MT_ORIENTATION,
|
|
||||||
orientation);
|
|
||||||
input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
|
|
||||||
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
|
|
||||||
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
|
|
||||||
|
|
||||||
set_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app->num_received++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -892,8 +858,7 @@ static void mt_sync_frame(struct mt_device *td, struct mt_application *app,
|
||||||
clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
|
clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mt_compute_timestamp(struct mt_application *app,
|
static int mt_compute_timestamp(struct mt_application *app, __s32 value)
|
||||||
struct hid_field *field, __s32 value)
|
|
||||||
{
|
{
|
||||||
long delta = value - app->prev_scantime;
|
long delta = value - app->prev_scantime;
|
||||||
unsigned long jdelta = jiffies_to_usecs(jiffies - app->jiffies);
|
unsigned long jdelta = jiffies_to_usecs(jiffies - app->jiffies);
|
||||||
|
@ -901,7 +866,7 @@ static int mt_compute_timestamp(struct mt_application *app,
|
||||||
app->jiffies = jiffies;
|
app->jiffies = jiffies;
|
||||||
|
|
||||||
if (delta < 0)
|
if (delta < 0)
|
||||||
delta += field->logical_maximum;
|
delta += app->scantime_logical_max;
|
||||||
|
|
||||||
/* HID_DG_SCANTIME is expressed in 100us, we want it in us. */
|
/* HID_DG_SCANTIME is expressed in 100us, we want it in us. */
|
||||||
delta *= 100;
|
delta *= 100;
|
||||||
|
@ -923,64 +888,69 @@ static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
|
static int mt_process_slot(struct mt_device *td, struct input_dev *input,
|
||||||
struct hid_usage *usage, __s32 value,
|
struct mt_application *app,
|
||||||
struct mt_application *app, bool first_packet)
|
struct mt_usages *slot)
|
||||||
{
|
{
|
||||||
struct mt_device *td = hid_get_drvdata(hid);
|
struct input_mt *mt = input->mt;
|
||||||
__s32 quirks = app->quirks;
|
__s32 quirks = app->quirks;
|
||||||
struct input_dev *input = field->hidinput->input;
|
bool valid = true;
|
||||||
|
bool confidence_state = true;
|
||||||
|
bool inrange_state = false;
|
||||||
|
int active;
|
||||||
|
int slotnum;
|
||||||
|
|
||||||
if (hid->claimed & HID_CLAIMED_INPUT) {
|
if (!slot)
|
||||||
switch (usage->hid) {
|
return -EINVAL;
|
||||||
case HID_DG_INRANGE:
|
|
||||||
if (quirks & MT_QUIRK_VALID_IS_INRANGE)
|
if ((quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
|
||||||
app->curvalid = value;
|
app->num_received >= app->num_expected)
|
||||||
if (quirks & MT_QUIRK_HOVERING)
|
return -EAGAIN;
|
||||||
app->curdata.inrange_state = value;
|
|
||||||
break;
|
if (!(quirks & MT_QUIRK_ALWAYS_VALID)) {
|
||||||
case HID_DG_TIPSWITCH:
|
if (quirks & MT_QUIRK_VALID_IS_INRANGE)
|
||||||
if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
|
valid = *slot->inrange_state;
|
||||||
app->curvalid = value;
|
if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
|
||||||
app->curdata.touch_state = value;
|
valid = *slot->tip_state;
|
||||||
break;
|
if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
|
||||||
case HID_DG_CONFIDENCE:
|
valid = *slot->confidence_state;
|
||||||
if (quirks & MT_QUIRK_CONFIDENCE)
|
|
||||||
app->curdata.confidence_state = value;
|
if (!valid)
|
||||||
if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
|
return 0;
|
||||||
app->curvalid = value;
|
}
|
||||||
break;
|
|
||||||
case HID_DG_CONTACTID:
|
slotnum = mt_compute_slot(td, app, slot, input);
|
||||||
app->curdata.contactid = value;
|
if (slotnum < 0 || slotnum >= td->maxcontacts)
|
||||||
break;
|
return 0;
|
||||||
case HID_DG_TIPPRESSURE:
|
|
||||||
app->curdata.p = value;
|
if ((quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) {
|
||||||
break;
|
struct input_mt_slot *i_slot = &mt->slots[slotnum];
|
||||||
case HID_GD_X:
|
|
||||||
if (usage->code == ABS_MT_TOOL_X)
|
if (input_mt_is_active(i_slot) &&
|
||||||
app->curdata.cx = value;
|
input_mt_is_used(mt, i_slot))
|
||||||
else
|
return -EAGAIN;
|
||||||
app->curdata.x = value;
|
}
|
||||||
break;
|
|
||||||
case HID_GD_Y:
|
if (quirks & MT_QUIRK_CONFIDENCE)
|
||||||
if (usage->code == ABS_MT_TOOL_Y)
|
confidence_state = *slot->confidence_state;
|
||||||
app->curdata.cy = value;
|
|
||||||
else
|
if (quirks & MT_QUIRK_HOVERING)
|
||||||
app->curdata.y = value;
|
inrange_state = *slot->inrange_state;
|
||||||
break;
|
|
||||||
case HID_DG_WIDTH:
|
active = (*slot->tip_state || inrange_state) && confidence_state;
|
||||||
app->curdata.w = value;
|
|
||||||
break;
|
input_mt_slot(input, slotnum);
|
||||||
case HID_DG_HEIGHT:
|
input_mt_report_slot_state(input, MT_TOOL_FINGER, active);
|
||||||
app->curdata.h = value;
|
if (active) {
|
||||||
break;
|
/* this finger is in proximity of the sensor */
|
||||||
case HID_DG_SCANTIME:
|
int wide = (*slot->w > *slot->h);
|
||||||
app->timestamp = mt_compute_timestamp(app, field,
|
int major = max(*slot->w, *slot->h);
|
||||||
value);
|
int minor = min(*slot->w, *slot->h);
|
||||||
break;
|
int orientation = wide;
|
||||||
case HID_DG_CONTACTCOUNT:
|
int max_azimuth;
|
||||||
break;
|
int azimuth;
|
||||||
case HID_DG_AZIMUTH:
|
|
||||||
|
if (slot->a != DEFAULT_ZERO) {
|
||||||
/*
|
/*
|
||||||
* Azimuth is counter-clockwise and ranges from [0, MAX)
|
* Azimuth is counter-clockwise and ranges from [0, MAX)
|
||||||
* (a full revolution). Convert it to clockwise ranging
|
* (a full revolution). Convert it to clockwise ranging
|
||||||
|
@ -991,52 +961,76 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
|
||||||
* out of range to [-MAX/2, MAX/2] to report an upside
|
* out of range to [-MAX/2, MAX/2] to report an upside
|
||||||
* down ellipsis.
|
* down ellipsis.
|
||||||
*/
|
*/
|
||||||
if (value > field->logical_maximum / 2)
|
azimuth = *slot->a;
|
||||||
value -= field->logical_maximum;
|
max_azimuth = input_abs_get_max(input,
|
||||||
app->curdata.a = -value;
|
ABS_MT_ORIENTATION);
|
||||||
app->curdata.has_azimuth = true;
|
if (azimuth > max_azimuth * 2)
|
||||||
break;
|
azimuth -= max_azimuth * 4;
|
||||||
case HID_DG_TOUCH:
|
orientation = -azimuth;
|
||||||
/* do nothing */
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
/*
|
||||||
/*
|
* divided by two to match visual scale of touch
|
||||||
* For Win8 PTP touchpads we should only look at
|
* for devices with this quirk
|
||||||
* non finger/touch events in the first_packet of
|
*/
|
||||||
* a (possible) multi-packet frame.
|
if (quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
|
||||||
*/
|
major = major >> 1;
|
||||||
if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
|
minor = minor >> 1;
|
||||||
!first_packet)
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x);
|
||||||
* For Win8 PTP touchpads we map both the clickpad click
|
input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y);
|
||||||
* and any "external" left buttons to BTN_LEFT if a
|
input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx);
|
||||||
* device claims to have both we need to report 1 for
|
input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy);
|
||||||
* BTN_LEFT if either is pressed, so we or all values
|
input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state);
|
||||||
* together and report the result in mt_sync_frame().
|
input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation);
|
||||||
*/
|
input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->p);
|
||||||
if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
|
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
|
||||||
usage->type == EV_KEY && usage->code == BTN_LEFT) {
|
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
|
||||||
app->left_button_state |= value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (usage->type)
|
set_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
|
||||||
input_event(input, usage->type, usage->code,
|
}
|
||||||
value);
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mt_process_mt_event(struct hid_device *hid,
|
||||||
|
struct mt_application *app,
|
||||||
|
struct hid_field *field,
|
||||||
|
struct hid_usage *usage,
|
||||||
|
__s32 value,
|
||||||
|
bool first_packet)
|
||||||
|
{
|
||||||
|
__s32 quirks = app->quirks;
|
||||||
|
struct input_dev *input = field->hidinput->input;
|
||||||
|
|
||||||
|
if (!usage->type || !(hid->claimed & HID_CLAIMED_INPUT))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (quirks & MT_QUIRK_WIN8_PTP_BUTTONS) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For Win8 PTP touchpads we should only look at
|
||||||
|
* non finger/touch events in the first_packet of a
|
||||||
|
* (possible) multi-packet frame.
|
||||||
|
*/
|
||||||
|
if (!first_packet)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For Win8 PTP touchpads we map both the clickpad click
|
||||||
|
* and any "external" left buttons to BTN_LEFT if a
|
||||||
|
* device claims to have both we need to report 1 for
|
||||||
|
* BTN_LEFT if either is pressed, so we or all values
|
||||||
|
* together and report the result in mt_sync_frame().
|
||||||
|
*/
|
||||||
|
if (usage->type == EV_KEY && usage->code == BTN_LEFT) {
|
||||||
|
app->left_button_state |= value;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usage->usage_index + 1 == field->report_count) {
|
|
||||||
/* we only take into account the last report. */
|
|
||||||
if (usage->hid == app->last_slot_field)
|
|
||||||
mt_complete_slot(td, app,
|
|
||||||
field->hidinput->input);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input_event(input, usage->type, usage->code, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mt_touch_report(struct hid_device *hid,
|
static void mt_touch_report(struct hid_device *hid,
|
||||||
|
@ -1046,6 +1040,8 @@ static void mt_touch_report(struct hid_device *hid,
|
||||||
struct hid_report *report = rdata->report;
|
struct hid_report *report = rdata->report;
|
||||||
struct mt_application *app = rdata->application;
|
struct mt_application *app = rdata->application;
|
||||||
struct hid_field *field;
|
struct hid_field *field;
|
||||||
|
struct input_dev *input;
|
||||||
|
struct mt_usages *slot;
|
||||||
bool first_packet;
|
bool first_packet;
|
||||||
unsigned count;
|
unsigned count;
|
||||||
int r, n;
|
int r, n;
|
||||||
|
@ -1056,18 +1052,16 @@ static void mt_touch_report(struct hid_device *hid,
|
||||||
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
|
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
scantime = *app->scantime;
|
||||||
|
app->timestamp = mt_compute_timestamp(app, scantime);
|
||||||
|
if (app->raw_cc != DEFAULT_ZERO)
|
||||||
|
contact_count = *app->raw_cc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Includes multi-packet support where subsequent
|
* Includes multi-packet support where subsequent
|
||||||
* packets are sent with zero contactcount.
|
* packets are sent with zero contactcount.
|
||||||
*/
|
*/
|
||||||
if (app->scantime_index >= 0) {
|
if (contact_count >= 0) {
|
||||||
field = report->field[app->scantime_index];
|
|
||||||
scantime = field->value[app->scantime_val_index];
|
|
||||||
}
|
|
||||||
if (app->cc_index >= 0) {
|
|
||||||
field = report->field[app->cc_index];
|
|
||||||
contact_count = field->value[app->cc_value_index];
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For Win8 PTPs the first packet (td->num_received == 0) may
|
* For Win8 PTPs the first packet (td->num_received == 0) may
|
||||||
* have a contactcount of 0 if there only is a button event.
|
* have a contactcount of 0 if there only is a button event.
|
||||||
|
@ -1086,6 +1080,14 @@ static void mt_touch_report(struct hid_device *hid,
|
||||||
app->prev_scantime = scantime;
|
app->prev_scantime = scantime;
|
||||||
|
|
||||||
first_packet = app->num_received == 0;
|
first_packet = app->num_received == 0;
|
||||||
|
|
||||||
|
input = report->field[0]->hidinput->input;
|
||||||
|
|
||||||
|
list_for_each_entry(slot, &app->mt_usages, list) {
|
||||||
|
if (!mt_process_slot(td, input, app, slot))
|
||||||
|
app->num_received++;
|
||||||
|
}
|
||||||
|
|
||||||
for (r = 0; r < report->maxfield; r++) {
|
for (r = 0; r < report->maxfield; r++) {
|
||||||
field = report->field[r];
|
field = report->field[r];
|
||||||
count = field->report_count;
|
count = field->report_count;
|
||||||
|
@ -1094,12 +1096,13 @@ static void mt_touch_report(struct hid_device *hid,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (n = 0; n < count; n++)
|
for (n = 0; n < count; n++)
|
||||||
mt_process_mt_event(hid, field, &field->usage[n],
|
mt_process_mt_event(hid, app, field,
|
||||||
field->value[n], app, first_packet);
|
&field->usage[n], field->value[n],
|
||||||
|
first_packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (app->num_received >= app->num_expected)
|
if (app->num_received >= app->num_expected)
|
||||||
mt_sync_frame(td, app, report->field[0]->hidinput->input);
|
mt_sync_frame(td, app, input);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Windows 8 specs says 2 things:
|
* Windows 8 specs says 2 things:
|
||||||
|
@ -1391,7 +1394,7 @@ static void mt_post_parse_default_settings(struct mt_device *td,
|
||||||
__s32 quirks = app->quirks;
|
__s32 quirks = app->quirks;
|
||||||
|
|
||||||
/* unknown serial device needs special quirks */
|
/* unknown serial device needs special quirks */
|
||||||
if (app->touches_by_report == 1) {
|
if (list_is_singular(&app->mt_usages)) {
|
||||||
quirks |= MT_QUIRK_ALWAYS_VALID;
|
quirks |= MT_QUIRK_ALWAYS_VALID;
|
||||||
quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
|
quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
|
||||||
quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
|
quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
|
||||||
|
@ -1404,16 +1407,7 @@ static void mt_post_parse_default_settings(struct mt_device *td,
|
||||||
|
|
||||||
static void mt_post_parse(struct mt_device *td, struct mt_application *app)
|
static void mt_post_parse(struct mt_device *td, struct mt_application *app)
|
||||||
{
|
{
|
||||||
struct mt_fields *f = td->fields;
|
if (!app->have_contact_count)
|
||||||
|
|
||||||
if (app->touches_by_report > 0) {
|
|
||||||
int field_count_per_touch;
|
|
||||||
|
|
||||||
field_count_per_touch = f->length / app->touches_by_report;
|
|
||||||
app->last_slot_field = f->usages[field_count_per_touch - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (app->cc_index < 0)
|
|
||||||
app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
|
app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1596,13 +1590,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
INIT_LIST_HEAD(&td->applications);
|
INIT_LIST_HEAD(&td->applications);
|
||||||
INIT_LIST_HEAD(&td->reports);
|
INIT_LIST_HEAD(&td->reports);
|
||||||
|
|
||||||
td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!td->fields) {
|
|
||||||
dev_err(&hdev->dev, "cannot allocate multitouch fields data\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
|
if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
|
||||||
td->serial_maybe = true;
|
td->serial_maybe = true;
|
||||||
|
|
||||||
|
@ -1638,10 +1625,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
|
|
||||||
mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
|
mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
|
||||||
|
|
||||||
/* release .fields memory as it is not used anymore */
|
|
||||||
devm_kfree(&hdev->dev, td->fields);
|
|
||||||
td->fields = NULL;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue