Commit 16501e84 authored by Jiri Kosina's avatar Jiri Kosina

Merge branch 'for-4.19/multitouch-multiaxis' into for-linus

Multitouch updates:

- Dial support
- Palm rejection for touchscreens
- a few small assorted fixes
parents f5dd8071 28a042a3
......@@ -310,12 +310,12 @@ ABS_MT_TOOL_Y
ABS_MT_TOOL_TYPE
The type of approaching tool. A lot of kernel drivers cannot distinguish
between different tool types, such as a finger or a pen. In such cases, the
event should be omitted. The protocol currently supports MT_TOOL_FINGER,
MT_TOOL_PEN, and MT_TOOL_PALM [#f2]_. For type B devices, this event is
handled by input core; drivers should instead use
input_mt_report_slot_state(). A contact's ABS_MT_TOOL_TYPE may change over
time while still touching the device, because the firmware may not be able
to determine which tool is being used when it first appears.
event should be omitted. The protocol currently mainly supports
MT_TOOL_FINGER, MT_TOOL_PEN, and MT_TOOL_PALM [#f2]_.
For type B devices, this event is handled by input core; drivers should
instead use input_mt_report_slot_state(). A contact's ABS_MT_TOOL_TYPE may
change over time while still touching the device, because the firmware may
not be able to determine which tool is being used when it first appears.
ABS_MT_BLOB_ID
The BLOB_ID groups several packets together into one arbitrarily shaped
......
......@@ -128,9 +128,19 @@ static int open_collection(struct hid_parser *parser, unsigned type)
usage = parser->local.usage[0];
if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
hid_err(parser->device, "collection stack overflow\n");
return -EINVAL;
if (parser->collection_stack_ptr == parser->collection_stack_size) {
unsigned int *collection_stack;
unsigned int new_size = parser->collection_stack_size +
HID_COLLECTION_STACK_SIZE;
collection_stack = krealloc(parser->collection_stack,
new_size * sizeof(unsigned int),
GFP_KERNEL);
if (!collection_stack)
return -ENOMEM;
parser->collection_stack = collection_stack;
parser->collection_stack_size = new_size;
}
if (parser->device->maxcollection == parser->device->collection_size) {
......@@ -840,6 +850,7 @@ static int hid_scan_report(struct hid_device *hid)
break;
}
kfree(parser->collection_stack);
vfree(parser);
return 0;
}
......
......@@ -1550,6 +1550,9 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid,
case HID_GD_WIRELESS_RADIO_CTLS:
suffix = "Wireless Radio Control";
break;
case HID_GD_SYSTEM_MULTIAXIS:
suffix = "System Multi Axis";
break;
default:
break;
}
......
......@@ -22,12 +22,13 @@
#include "hid-ids.h"
#define MS_HIDINPUT 0x01
#define MS_ERGONOMY 0x02
#define MS_PRESENTER 0x04
#define MS_RDESC 0x08
#define MS_NOGET 0x10
#define MS_DUPLICATE_USAGES 0x20
#define MS_HIDINPUT BIT(0)
#define MS_ERGONOMY BIT(1)
#define MS_PRESENTER BIT(2)
#define MS_RDESC BIT(3)
#define MS_NOGET BIT(4)
#define MS_DUPLICATE_USAGES BIT(5)
#define MS_SURFACE_DIAL BIT(6)
static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
......@@ -130,6 +131,30 @@ static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage,
return 1;
}
static int ms_surface_dial_quirk(struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max)
{
switch (usage->hid & HID_USAGE_PAGE) {
case 0xff070000:
/* fall-through */
case HID_UP_DIGITIZER:
/* ignore those axis */
return -1;
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
/* fall-through */
case HID_GD_Y:
/* fall-through */
case HID_GD_RFKILL_BTN:
/* ignore those axis */
return -1;
}
}
return 0;
}
static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
......@@ -146,6 +171,13 @@ static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
ms_presenter_8k_quirk(hi, usage, bit, max))
return 1;
if (quirks & MS_SURFACE_DIAL) {
int ret = ms_surface_dial_quirk(hi, field, usage, bit, max);
if (ret)
return ret;
}
return 0;
}
......@@ -229,6 +261,9 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (quirks & MS_NOGET)
hdev->quirks |= HID_QUIRK_NOGET;
if (quirks & MS_SURFACE_DIAL)
hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
......@@ -281,6 +316,8 @@ static const struct hid_device_id ms_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
.driver_data = MS_PRESENTER },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, 0x091B),
.driver_data = MS_SURFACE_DIAL },
{ }
};
MODULE_DEVICE_TABLE(hid, ms_devices);
......
......@@ -28,14 +28,11 @@
*/
/*
* This driver is regularly tested thanks to the tool hid-test[1].
* This tool relies on hid-replay[2] and a database of hid devices[3].
* This driver is regularly tested thanks to the test suite in hid-tools[1].
* Please run these regression tests before patching this module so that
* your patch won't break existing known devices.
*
* [1] https://github.com/bentiss/hid-test
* [2] https://github.com/bentiss/hid-replay
* [3] https://github.com/bentiss/hid-devices
* [1] https://gitlab.freedesktop.org/libevdev/hid-tools
*/
#include <linux/device.h>
......@@ -90,13 +87,54 @@ enum latency_mode {
#define MT_IO_FLAGS_ACTIVE_SLOTS 1
#define MT_IO_FLAGS_PENDING_SLOTS 2
struct mt_slot {
__s32 x, y, cx, cy, p, w, h, a;
__s32 contactid; /* the device ContactID assigned to this slot */
bool touch_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? */
bool has_azimuth; /* the contact reports azimuth */
static const bool mtrue = true; /* default for true */
static const bool mfalse; /* default for false */
static const __s32 mzero; /* default for 0 */
#define DEFAULT_TRUE ((void *)&mtrue)
#define DEFAULT_FALSE ((void *)&mfalse)
#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 list_head list;
unsigned int application;
struct list_head mt_usages; /* mt usages list */
__s32 quirks;
__s32 *scantime; /* scantime reported */
__s32 scantime_logical_max; /* max value for raw scantime */
__s32 *raw_cc; /* contact count in the report */
int left_button_state; /* left button state */
unsigned int mt_flags; /* flags to pass to input-mt */
unsigned long *pending_palm_slots; /* slots where we reported palm
* and need to release */
__u8 num_received; /* how many contacts we received */
__u8 num_expected; /* expected last contact index */
__u8 buttons_count; /* number of physical buttons per touchpad */
__u8 touches_by_report; /* how many touches are present in one report:
* 1 means we should use a serial protocol
* > 1 means hybrid (multitouch) protocol
*/
__s32 dev_time; /* the scan time provided by the device */
unsigned long jiffies; /* the frame's jiffies */
int timestamp; /* the timestamp to be sent */
int prev_scantime; /* scantime reported previously */
bool have_contact_count;
};
struct mt_class {
......@@ -111,46 +149,30 @@ struct mt_class {
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 list_head list;
struct hid_report *report;
struct mt_application *application;
bool is_mt_collection;
};
struct mt_device {
struct mt_slot curdata; /* placeholder of incoming data */
struct mt_class mtclass; /* our mt device class */
struct timer_list release_timer; /* to release sticky fingers */
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_*) */
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 */
int prev_scantime; /* scantime reported in the previous packet */
int left_button_state; /* left button state */
unsigned last_slot_field; /* the last field of a slot */
unsigned mt_report_id; /* the report ID of the multitouch device */
__u8 inputmode_value; /* InputMode HID feature value */
__u8 num_received; /* how many contacts we received */
__u8 num_expected; /* expected last contact index */
__u8 maxcontacts;
__u8 touches_by_report; /* how many touches are present in one report:
* 1 means we should use a serial protocol
* > 1 means hybrid (multitouch) protocol */
__u8 buttons_count; /* number of physical buttons per touchpad */
bool is_buttonpad; /* is this device a button pad? */
bool serial_maybe; /* need to check for serial protocol */
bool curvalid; /* is the current contact valid? */
unsigned mt_flags; /* flags to pass to input-mt */
__s32 dev_time; /* the scan time provided by the device */
unsigned long jiffies; /* the frame's jiffies */
int timestamp; /* the timestamp to be sent */
struct list_head applications;
struct list_head reports;
};
static void mt_post_parse_default_settings(struct mt_device *td);
static void mt_post_parse(struct mt_device *td);
static void mt_post_parse_default_settings(struct mt_device *td,
struct mt_application *app);
static void mt_post_parse(struct mt_device *td, struct mt_application *app);
/* classes of device behavior */
#define MT_CLS_DEFAULT 0x0001
......@@ -203,15 +225,16 @@ static void mt_post_parse(struct mt_device *td);
* to a valid contact that was just read.
*/
static int cypress_compute_slot(struct mt_device *td)
static int cypress_compute_slot(struct mt_application *application,
struct mt_usages *slot)
{
if (td->curdata.contactid != 0 || td->num_received == 0)
return td->curdata.contactid;
if (*slot->contactid != 0 || application->num_received == 0)
return *slot->contactid;
else
return -1;
}
static struct mt_class mt_classes[] = {
static const struct mt_class mt_classes[] = {
{ .name = MT_CLS_DEFAULT,
.quirks = MT_QUIRK_ALWAYS_VALID |
MT_QUIRK_CONTACT_CNT_ACCURATE },
......@@ -353,6 +376,7 @@ static ssize_t mt_set_quirks(struct device *dev,
{
struct hid_device *hdev = to_hid_device(dev);
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_application *application;
unsigned long val;
......@@ -361,8 +385,11 @@ static ssize_t mt_set_quirks(struct device *dev,
td->mtclass.quirks = val;
if (td->cc_index < 0)
td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
list_for_each_entry(application, &td->applications, list) {
application->quirks = val;
if (!application->have_contact_count)
application->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
}
return count;
}
......@@ -457,41 +484,199 @@ static void set_abs(struct input_dev *input, unsigned int code,
input_abs_set_res(input, code, hidinput_calc_abs_res(field, code));
}
static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
struct hid_input *hi)
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,
unsigned int application)
{
struct mt_application *mt_application;
mt_application = devm_kzalloc(&td->hdev->dev, sizeof(*mt_application),
GFP_KERNEL);
if (!mt_application)
return NULL;
mt_application->application = application;
INIT_LIST_HEAD(&mt_application->mt_usages);
if (application == HID_DG_TOUCHSCREEN)
mt_application->mt_flags |= INPUT_MT_DIRECT;
/*
* Model touchscreens providing buttons as touchpads.
*/
if (application == HID_DG_TOUCHPAD) {
mt_application->mt_flags |= INPUT_MT_POINTER;
td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
}
mt_application->scantime = DEFAULT_ZERO;
mt_application->raw_cc = DEFAULT_ZERO;
mt_application->quirks = td->mtclass.quirks;
list_add_tail(&mt_application->list, &td->applications);
return mt_application;
}
static struct mt_application *mt_find_application(struct mt_device *td,
unsigned int application)
{
struct mt_application *tmp, *mt_application = NULL;
list_for_each_entry(tmp, &td->applications, list) {
if (application == tmp->application) {
mt_application = tmp;
break;
}
}
if (!mt_application)
mt_application = mt_allocate_application(td, application);
return mt_application;
}
static struct mt_report_data *mt_allocate_report_data(struct mt_device *td,
struct hid_report *report)
{
struct mt_report_data *rdata;
struct hid_field *field;
int r, n;
rdata = devm_kzalloc(&td->hdev->dev, sizeof(*rdata), GFP_KERNEL);
if (!rdata)
return NULL;
rdata->report = report;
rdata->application = mt_find_application(td, report->application);
if (!rdata->application) {
devm_kfree(&td->hdev->dev, rdata);
return NULL;
}
for (r = 0; r < report->maxfield; r++) {
field = report->field[r];
if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
continue;
for (n = 0; n < field->report_count; n++) {
if (field->usage[n].hid == HID_DG_CONTACTID)
rdata->is_mt_collection = true;
}
}
list_add_tail(&rdata->list, &td->reports);
return rdata;
}
static struct mt_report_data *mt_find_report_data(struct mt_device *td,
struct hid_report *report)
{
struct mt_fields *f = td->fields;
struct mt_report_data *tmp, *rdata = NULL;
if (f->length >= HID_MAX_FIELDS)
list_for_each_entry(tmp, &td->reports, list) {
if (report == tmp->report) {
rdata = tmp;
break;
}
}
if (!rdata)
rdata = mt_allocate_report_data(td, report);
return rdata;
}
static void mt_store_field(struct hid_device *hdev,
struct mt_application *application,
__s32 *value,
size_t offset)
{
struct mt_usages *usage;
__s32 **target;
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;
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,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
unsigned long **bit, int *max, struct mt_application *app)
{
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_class *cls = &td->mtclass;
int code;
struct hid_usage *prev_usage = NULL;
if (field->application == HID_DG_TOUCHSCREEN)
td->mt_flags |= INPUT_MT_DIRECT;
/*
* Model touchscreens providing buttons as touchpads.
*/
if (field->application == HID_DG_TOUCHPAD ||
if (field->application == HID_DG_TOUCHSCREEN &&
(usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
td->mt_flags |= INPUT_MT_POINTER;
app->mt_flags |= INPUT_MT_POINTER;
td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
}
/* count the buttons on touchpads */
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
td->buttons_count++;
app->buttons_count++;
if (usage->usage_index)
prev_usage = &field->usage[usage->usage_index - 1];
......@@ -502,33 +687,40 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
switch (usage->hid) {
case HID_GD_X:
if (prev_usage && (prev_usage->hid == usage->hid)) {
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOOL_X);
set_abs(hi->input, ABS_MT_TOOL_X, field,
cls->sn_move);
code = ABS_MT_TOOL_X;
MT_STORE_FIELD(cx);
} else {
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X);
set_abs(hi->input, ABS_MT_POSITION_X, field,
cls->sn_move);
code = ABS_MT_POSITION_X;
MT_STORE_FIELD(x);
}
set_abs(hi->input, code, field, cls->sn_move);
/*
* A system multi-axis that exports X and Y has a high
* chance of being used directly on a surface
*/
if (field->application == HID_GD_SYSTEM_MULTIAXIS) {
__set_bit(INPUT_PROP_DIRECT,
hi->input->propbit);
input_set_abs_params(hi->input,
ABS_MT_TOOL_TYPE,
MT_TOOL_DIAL,
MT_TOOL_DIAL, 0, 0);
}
mt_store_field(usage, td, hi);
return 1;
case HID_GD_Y:
if (prev_usage && (prev_usage->hid == usage->hid)) {
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOOL_Y);
set_abs(hi->input, ABS_MT_TOOL_Y, field,
cls->sn_move);
code = ABS_MT_TOOL_Y;
MT_STORE_FIELD(cy);
} else {
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y);
set_abs(hi->input, ABS_MT_POSITION_Y, field,
cls->sn_move);
code = ABS_MT_POSITION_Y;
MT_STORE_FIELD(y);
}
mt_store_field(usage, td, hi);
set_abs(hi->input, code, field, cls->sn_move);
return 1;
}
return 0;
......@@ -536,43 +728,45 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_UP_DIGITIZER:
switch (usage->hid) {
case HID_DG_INRANGE:
if (cls->quirks & MT_QUIRK_HOVERING) {
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_DISTANCE);
if (app->quirks & MT_QUIRK_HOVERING) {
input_set_abs_params(hi->input,
ABS_MT_DISTANCE, 0, 1, 0, 0);
}
mt_store_field(usage, td, hi);
MT_STORE_FIELD(inrange_state);
return 1;
case HID_DG_CONFIDENCE:
if ((cls->name == MT_CLS_WIN_8 ||
cls->name == MT_CLS_WIN_8_DUAL) &&
field->application == HID_DG_TOUCHPAD)
cls->quirks |= MT_QUIRK_CONFIDENCE;
mt_store_field(usage, td, hi);
(field->application == HID_DG_TOUCHPAD ||
field->application == HID_DG_TOUCHSCREEN))
app->quirks |= MT_QUIRK_CONFIDENCE;
if (app->quirks & MT_QUIRK_CONFIDENCE)
input_set_abs_params(hi->input,
ABS_MT_TOOL_TYPE,
MT_TOOL_FINGER,
MT_TOOL_PALM, 0, 0);
MT_STORE_FIELD(confidence_state);
return 1;
case HID_DG_TIPSWITCH:
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
mt_store_field(usage, td, hi);
if (field->application != HID_GD_SYSTEM_MULTIAXIS)
input_set_capability(hi->input,
EV_KEY, BTN_TOUCH);
MT_STORE_FIELD(tip_state);
return 1;
case HID_DG_CONTACTID:
mt_store_field(usage, td, hi);
td->touches_by_report++;
td->mt_report_id = field->report->id;
MT_STORE_FIELD(contactid);
app->touches_by_report++;
return 1;
case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MAJOR);
if (!(cls->quirks & MT_QUIRK_NO_AREA))
if (!(app->quirks & MT_QUIRK_NO_AREA))
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
cls->sn_width);
mt_store_field(usage, td, hi);
MT_STORE_FIELD(w);
return 1;
case HID_DG_HEIGHT:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MINOR);
if (!(cls->quirks & MT_QUIRK_NO_AREA)) {
if (!(app->quirks & MT_QUIRK_NO_AREA)) {
set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
cls->sn_height);
......@@ -585,41 +779,23 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
input_set_abs_params(hi->input,
ABS_MT_ORIENTATION, 0, 1, 0, 0);
}
mt_store_field(usage, td, hi);
MT_STORE_FIELD(h);
return 1;
case HID_DG_TIPPRESSURE:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_PRESSURE);
set_abs(hi->input, ABS_MT_PRESSURE, field,
cls->sn_pressure);
mt_store_field(usage, td, hi);
MT_STORE_FIELD(p);
return 1;
case HID_DG_SCANTIME:
hid_map_usage(hi, usage, bit, max,
EV_MSC, MSC_TIMESTAMP);
input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP);
/* Ignore if indexes are out of bounds. */
if (field->index >= field->report->maxfield ||
usage->usage_index >= field->report_count)
return 1;
td->scantime_index = field->index;
td->scantime_val_index = usage->usage_index;
/*
* We don't set td->last_slot_field as scan time is
* global to the report.
*/
app->scantime = &field->value[usage->usage_index];
app->scantime_logical_max = field->logical_maximum;
return 1;
case HID_DG_CONTACTCOUNT:
/* Ignore if indexes are out of bounds. */
if (field->index >= field->report->maxfield ||
usage->usage_index >= field->report_count)
return 1;
td->cc_index = field->index;
td->cc_value_index = usage->usage_index;
app->have_contact_count = true;
app->raw_cc = &field->value[usage->usage_index];
return 1;
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
* revolution. Set ABS_MT_ORIENTATION to a quarter of
......@@ -630,11 +806,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
field->logical_maximum / 4,
cls->sn_move ?
field->logical_maximum / cls->sn_move : 0, 0);
mt_store_field(usage, td, hi);
MT_STORE_FIELD(a);
return 1;
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;
case HID_DG_TOUCH:
/* Legacy devices use TIPSWITCH and not TOUCH.
......@@ -650,10 +825,14 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
* MS PTP spec says that external buttons left and right have
* usages 2 and 3.
*/
if ((cls->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
field->application == HID_DG_TOUCHPAD &&
(usage->hid & HID_USAGE) > 1)
code--;
if (field->application == HID_GD_SYSTEM_MULTIAXIS)
code = BTN_0 + ((usage->hid - 1) & HID_USAGE);
hid_map_usage(hi, usage, bit, max, EV_KEY, code);
input_set_capability(hi->input, EV_KEY, code);
return 1;
......@@ -666,110 +845,68 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 0;
}
static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
struct mt_usages *slot,
struct input_dev *input)
{
__s32 quirks = td->mtclass.quirks;
__s32 quirks = app->quirks;
if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
return td->curdata.contactid;
return *slot->contactid;
if (quirks & MT_QUIRK_CYPRESS)
return cypress_compute_slot(td);
return cypress_compute_slot(app, slot);
if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
return td->num_received;
return app->num_received;
if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
return td->curdata.contactid - 1;
return *slot->contactid - 1;
return input_mt_get_slot_by_key(input, td->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 input_dev *input)
static void mt_release_pending_palms(struct mt_device *td,
struct mt_application *app,
struct input_dev *input)
{
if ((td->mtclass.quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
td->num_received >= td->num_expected)
return;
if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
int active;
int slotnum = mt_compute_slot(td, input);
struct mt_slot *s = &td->curdata;
struct input_mt *mt = input->mt;
int slotnum;
bool need_sync = false;
if (slotnum < 0 || slotnum >= td->maxcontacts)
return;
if ((td->mtclass.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 (!(td->mtclass.quirks & MT_QUIRK_CONFIDENCE))
s->confidence_state = true;
active = (s->touch_state || s->inrange_state) &&
s->confidence_state;
for_each_set_bit(slotnum, app->pending_palm_slots, td->maxcontacts) {
clear_bit(slotnum, app->pending_palm_slots);
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;
input_mt_report_slot_state(input, MT_TOOL_PALM, false);
if (s->has_azimuth)
orientation = s->a;
/*
* divided by two to match visual scale of touch
* for devices with this quirk
*/
if (td->mtclass.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);
}
need_sync = true;
}
td->num_received++;
if (need_sync) {
input_mt_sync_frame(input);
input_sync(input);
}
}
/*
* this function is called when a whole packet has been received and processed,
* so that it can decide what to send to the input layer.
*/
static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
static void mt_sync_frame(struct mt_device *td, struct mt_application *app,
struct input_dev *input)
{
if (td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS)
input_event(input, EV_KEY, BTN_LEFT, td->left_button_state);
if (app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS)
input_event(input, EV_KEY, BTN_LEFT, app->left_button_state);
input_mt_sync_frame(input);
input_event(input, EV_MSC, MSC_TIMESTAMP, td->timestamp);
input_event(input, EV_MSC, MSC_TIMESTAMP, app->timestamp);
input_sync(input);
td->num_received = 0;
td->left_button_state = 0;
mt_release_pending_palms(td, app, input);
app->num_received = 0;
app->left_button_state = 0;
if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags))
set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags);
else
......@@ -777,17 +914,15 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
}
static int mt_compute_timestamp(struct mt_device *td, struct hid_field *field,
__s32 value)
static int mt_compute_timestamp(struct mt_application *app, __s32 value)
{
long delta = value - td->dev_time;
unsigned long jdelta = jiffies_to_usecs(jiffies - td->jiffies);
long delta = value - app->prev_scantime;
unsigned long jdelta = jiffies_to_usecs(jiffies - app->jiffies);
td->jiffies = jiffies;
td->dev_time = value;
app->jiffies = jiffies;
if (delta < 0)
delta += field->logical_maximum;
delta += app->scantime_logical_max;
/* HID_DG_SCANTIME is expressed in 100us, we want it in us. */
delta *= 100;
......@@ -796,7 +931,7 @@ static int mt_compute_timestamp(struct mt_device *td, struct hid_field *field,
/* No data received for a while, resync the timestamp. */
return 0;
else
return td->timestamp + delta;
return app->timestamp + delta;
}
static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
......@@ -809,63 +944,90 @@ static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
return 1;
}
static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value,
bool first_packet)
static int mt_process_slot(struct mt_device *td, struct input_dev *input,
struct mt_application *app,
struct mt_usages *slot)
{
struct mt_device *td = hid_get_drvdata(hid);
__s32 quirks = td->mtclass.quirks;
struct input_dev *input = field->hidinput->input;
struct input_mt *mt = input->mt;
__s32 quirks = app->quirks;
bool valid = true;
bool confidence_state = true;
bool inrange_state = false;
int active;
int slotnum;
int tool = MT_TOOL_FINGER;
if (!slot)
return -EINVAL;
if (hid->claimed & HID_CLAIMED_INPUT) {
switch (usage->hid) {
case HID_DG_INRANGE:
if (quirks & MT_QUIRK_VALID_IS_INRANGE)
td->curvalid = value;
if (quirks & MT_QUIRK_HOVERING)
td->curdata.inrange_state = value;
break;
case HID_DG_TIPSWITCH:
if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
td->curvalid = value;
td->curdata.touch_state = value;
break;
case HID_DG_CONFIDENCE:
if (quirks & MT_QUIRK_CONFIDENCE)
td->curdata.confidence_state = value;
if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
td->curvalid = value;
break;
case HID_DG_CONTACTID:
td->curdata.contactid = value;
break;
case HID_DG_TIPPRESSURE:
td->curdata.p = value;
break;
case HID_GD_X:
if (usage->code == ABS_MT_TOOL_X)
td->curdata.cx = value;
else
td->curdata.x = value;
break;
case HID_GD_Y:
if (usage->code == ABS_MT_TOOL_Y)
td->curdata.cy = value;
else
td->curdata.y = value;
break;
case HID_DG_WIDTH:
td->curdata.w = value;
break;
case HID_DG_HEIGHT:
td->curdata.h = value;
break;
case HID_DG_SCANTIME:
td->timestamp = mt_compute_timestamp(td, field, value);
break;
case HID_DG_CONTACTCOUNT:
break;
case HID_DG_AZIMUTH:
if ((quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
app->num_received >= app->num_expected)
return -EAGAIN;
if (!(quirks & MT_QUIRK_ALWAYS_VALID)) {
if (quirks & MT_QUIRK_VALID_IS_INRANGE)
valid = *slot->inrange_state;
if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
valid = *slot->tip_state;
if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
valid = *slot->confidence_state;
if (!valid)
return 0;
}
slotnum = mt_compute_slot(td, app, slot, input);
if (slotnum < 0 || slotnum >= td->maxcontacts)
return 0;
if ((quirks & MT_QUIRK_IGNORE_DUPLICATES) && mt) {
struct input_mt_slot *i_slot = &mt->slots[slotnum];
if (input_mt_is_active(i_slot) &&
input_mt_is_used(mt, i_slot))
return -EAGAIN;
}
if (quirks & MT_QUIRK_CONFIDENCE)
confidence_state = *slot->confidence_state;
if (quirks & MT_QUIRK_HOVERING)
inrange_state = *slot->inrange_state;
active = *slot->tip_state || inrange_state;
if (app->application == HID_GD_SYSTEM_MULTIAXIS)
tool = MT_TOOL_DIAL;
else if (unlikely(!confidence_state)) {
tool = MT_TOOL_PALM;
if (!active &&
input_mt_is_active(&mt->slots[slotnum])) {
/*
* The non-confidence was reported for
* previously valid contact that is also no
* longer valid. We can't simply report
* lift-off as userspace will not be aware
* of non-confidence, so we need to split
* it into 2 events: active MT_TOOL_PALM
* and a separate liftoff.
*/
active = true;
set_bit(slotnum, app->pending_palm_slots);
}
}
input_mt_slot(input, slotnum);
input_mt_report_slot_state(input, tool, active);
if (active) {
/* this finger is in proximity of the sensor */
int wide = (*slot->w > *slot->h);
int major = max(*slot->w, *slot->h);
int minor = min(*slot->w, *slot->h);
int orientation = wide;
int max_azimuth;
int azimuth;
if (slot->a != DEFAULT_ZERO) {
/*
* Azimuth is counter-clockwise and ranges from [0, MAX)
* (a full revolution). Convert it to clockwise ranging
......@@ -876,77 +1038,107 @@ 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
* down ellipsis.
*/
if (value > field->logical_maximum / 2)
value -= field->logical_maximum;
td->curdata.a = -value;
td->curdata.has_azimuth = true;
break;
case HID_DG_TOUCH:
/* do nothing */
break;
azimuth = *slot->a;
max_azimuth = input_abs_get_max(input,
ABS_MT_ORIENTATION);
if (azimuth > max_azimuth * 2)
azimuth -= max_azimuth * 4;
orientation = -azimuth;
}
default:
if (quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
/*
* For Win8 PTP touchpads we should only look at
* non finger/touch events in the first_packet of
* a (possible) multi-packet frame.
* divided by two to match visual scale of touch
* for devices with this quirk
*/
if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
!first_packet)
return;
major = major >> 1;
minor = minor >> 1;
}
/*
* 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 ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
usage->type == EV_KEY && usage->code == BTN_LEFT) {
td->left_button_state |= value;
return;
}
input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y);
input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx);
input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy);
input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation);
input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->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);
}
if (usage->type)
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;
}
if (usage->usage_index + 1 == field->report_count) {
/* we only take into account the last report. */
if (usage->hid == td->last_slot_field)
mt_complete_slot(td, field->hidinput->input);
/*
* 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;
}
}
input_event(input, usage->type, usage->code, value);
}
static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
static void mt_touch_report(struct hid_device *hid,
struct mt_report_data *rdata)
{
struct mt_device *td = hid_get_drvdata(hid);
struct hid_report *report = rdata->report;
struct mt_application *app = rdata->application;
struct hid_field *field;
struct input_dev *input;
struct mt_usages *slot;
bool first_packet;
unsigned count;
int r, n, scantime = 0;
int r, n;
int scantime = 0;
int contact_count = -1;
/* sticky fingers release in progress, abort */
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
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
* packets are sent with zero contactcount.
*/
if (td->scantime_index >= 0) {
field = report->field[td->scantime_index];
scantime = field->value[td->scantime_val_index];
}
if (td->cc_index >= 0) {
struct hid_field *field = report->field[td->cc_index];
int value = field->value[td->cc_value_index];
if (contact_count >= 0) {
/*
* For Win8 PTPs the first packet (td->num_received == 0) may
* have a contactcount of 0 if there only is a button event.
......@@ -954,16 +1146,25 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
* of a possible multi-packet frame be checking that the
* timestamp has changed.
*/
if ((td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
td->num_received == 0 && td->prev_scantime != scantime)
td->num_expected = value;
if ((app->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
app->num_received == 0 &&
app->prev_scantime != scantime)
app->num_expected = contact_count;
/* A non 0 contact count always indicates a first packet */
else if (value)
td->num_expected = value;
else if (contact_count)
app->num_expected = contact_count;
}
app->prev_scantime = scantime;
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++;
}
td->prev_scantime = scantime;
first_packet = td->num_received == 0;
for (r = 0; r < report->maxfield; r++) {
field = report->field[r];
count = field->report_count;
......@@ -972,12 +1173,13 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
continue;
for (n = 0; n < count; n++)
mt_process_mt_event(hid, field, &field->usage[n],
field->value[n], first_packet);
mt_process_mt_event(hid, app, field,
&field->usage[n], field->value[n],
first_packet);
}
if (td->num_received >= td->num_expected)
mt_sync_frame(td, report->field[0]->hidinput->input);
if (app->num_received >= app->num_expected)
mt_sync_frame(td, app, input);
/*
* Windows 8 specs says 2 things:
......@@ -997,7 +1199,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
* only affect laggish machines and the ones that have a firmware
* defect.
*/
if (td->mtclass.quirks & MT_QUIRK_STICKY_FINGERS) {
if (app->quirks & MT_QUIRK_STICKY_FINGERS) {
if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags))
mod_timer(&td->release_timer,
jiffies + msecs_to_jiffies(100));
......@@ -1009,7 +1211,8 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
}
static int mt_touch_input_configured(struct hid_device *hdev,
struct hid_input *hi)
struct hid_input *hi,
struct mt_application *app)
{
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_class *cls = &td->mtclass;
......@@ -1019,28 +1222,36 @@ static int mt_touch_input_configured(struct hid_device *hdev,
if (!td->maxcontacts)
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
mt_post_parse(td);
mt_post_parse(td, app);
if (td->serial_maybe)
mt_post_parse_default_settings(td);
mt_post_parse_default_settings(td, app);
if (cls->is_indirect)
td->mt_flags |= INPUT_MT_POINTER;
app->mt_flags |= INPUT_MT_POINTER;
if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
td->mt_flags |= INPUT_MT_DROP_UNUSED;
if (app->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
app->mt_flags |= INPUT_MT_DROP_UNUSED;
/* check for clickpads */
if ((td->mt_flags & INPUT_MT_POINTER) && (td->buttons_count == 1))
if ((app->mt_flags & INPUT_MT_POINTER) &&
(app->buttons_count == 1))
td->is_buttonpad = true;
if (td->is_buttonpad)
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
ret = input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
app->pending_palm_slots = devm_kcalloc(&hi->input->dev,
BITS_TO_LONGS(td->maxcontacts),
sizeof(long),
GFP_KERNEL);
if (!app->pending_palm_slots)
return -ENOMEM;
ret = input_mt_init_slots(input, td->maxcontacts, app->mt_flags);
if (ret)
return ret;
td->mt_flags = 0;
app->mt_flags = 0;
return 0;
}
......@@ -1051,6 +1262,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
unsigned long **bit, int *max)
{
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_application *application;
struct mt_report_data *rdata;
rdata = mt_find_report_data(td, field->report);
if (!rdata) {
hid_err(hdev, "failed to allocate data for report\n");
return 0;
}
application = rdata->application;
/*
* If mtclass.export_all_inputs is not set, only map fields from
......@@ -1066,8 +1287,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
field->application != HID_GD_SYSTEM_CONTROL &&
field->application != HID_CP_CONSUMER_CONTROL &&
field->application != HID_GD_WIRELESS_RADIO_CTLS &&
field->application != HID_GD_SYSTEM_MULTIAXIS &&
!(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
td->mtclass.quirks & MT_QUIRK_ASUS_CUSTOM_UP))
application->quirks & MT_QUIRK_ASUS_CUSTOM_UP))
return -1;
/*
......@@ -1076,7 +1298,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
* map usages to input keys.
*/
if (field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
td->mtclass.quirks & MT_QUIRK_ASUS_CUSTOM_UP &&
application->quirks & MT_QUIRK_ASUS_CUSTOM_UP &&
(usage->hid & HID_USAGE_PAGE) == HID_UP_CUSTOM) {
set_bit(EV_REP, hi->input->evbit);
if (field->flags & HID_MAIN_ITEM_VARIABLE)
......@@ -1093,23 +1315,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 1;
}
/*
* some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
* for the stylus.
* The check for mt_report_id ensures we don't process
* HID_DG_CONTACTCOUNT from the pen report as it is outside the physical
* collection, but within the report ID.
*/
if (field->physical == HID_DG_STYLUS)
return 0;
else if ((field->physical == 0) &&
(field->report->id != td->mt_report_id) &&
(td->mt_report_id != -1))
return 0;
if (field->application == HID_DG_TOUCHSCREEN ||
field->application == HID_DG_TOUCHPAD)
return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
if (rdata->is_mt_collection)
return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
application);
/* let hid-core decide for the others */
return 0;
......@@ -1119,15 +1327,11 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
/*
* some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
* for the stylus.
*/
if (field->physical == HID_DG_STYLUS)
return 0;
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_report_data *rdata;
if (field->application == HID_DG_TOUCHSCREEN ||
field->application == HID_DG_TOUCHPAD) {
rdata = mt_find_report_data(td, field->report);
if (rdata && rdata->is_mt_collection) {
/* We own these mappings, tell hid-input to ignore them */
return -1;
}
......@@ -1140,8 +1344,10 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
struct mt_device *td = hid_get_drvdata(hid);
struct mt_report_data *rdata;
if (field->report->id == td->mt_report_id)
rdata = mt_find_report_data(td, field->report);
if (rdata && rdata->is_mt_collection)
return mt_touch_event(hid, field, usage, value);
return 0;
......@@ -1151,12 +1357,14 @@ static void mt_report(struct hid_device *hid, struct hid_report *report)
{
struct mt_device *td = hid_get_drvdata(hid);
struct hid_field *field = report->field[0];
struct mt_report_data *rdata;
if (!(hid->claimed & HID_CLAIMED_INPUT))
return;
if (report->id == td->mt_report_id)
return mt_touch_report(hid, report);
rdata = mt_find_report_data(td, report);
if (rdata && rdata->is_mt_collection)
return mt_touch_report(hid, rdata);
if (field && field->hidinput && field->hidinput->input)
input_sync(field->hidinput->input);
......@@ -1197,9 +1405,9 @@ static bool mt_need_to_apply_feature(struct hid_device *hdev,
return true;
case HID_DG_CONTACTMAX:
if (td->mtclass.maxcontacts) {
if (cls->maxcontacts) {
max = min_t(int, field->logical_maximum,
td->mtclass.maxcontacts);
cls->maxcontacts);
if (field->value[index] != max) {
field->value[index] = max;
return true;
......@@ -1259,12 +1467,13 @@ static void mt_set_modes(struct hid_device *hdev, enum latency_mode latency,
}
}
static void mt_post_parse_default_settings(struct mt_device *td)
static void mt_post_parse_default_settings(struct mt_device *td,
struct mt_application *app)
{
__s32 quirks = td->mtclass.quirks;
__s32 quirks = app->quirks;
/* unknown serial device needs special quirks */
if (td->touches_by_report == 1) {
if (list_is_singular(&app->mt_usages)) {
quirks |= MT_QUIRK_ALWAYS_VALID;
quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
......@@ -1272,21 +1481,13 @@ static void mt_post_parse_default_settings(struct mt_device *td)
quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
}
td->mtclass.quirks = quirks;
app->quirks = quirks;
}
static void mt_post_parse(struct mt_device *td)
static void mt_post_parse(struct mt_device *td, struct mt_application *app)
{
struct mt_fields *f = td->fields;
struct mt_class *cls = &td->mtclass;
if (td->touches_by_report > 0) {
int field_count_per_touch = f->length / td->touches_by_report;
td->last_slot_field = f->usages[field_count_per_touch - 1];
}
if (td->cc_index < 0)
cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
if (!app->have_contact_count)
app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
}
static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
......@@ -1295,13 +1496,24 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
char *name;
const char *suffix = NULL;
unsigned int application = 0;
struct mt_report_data *rdata;
struct mt_application *mt_application = NULL;
struct hid_report *report;
int ret;
list_for_each_entry(report, &hi->reports, hidinput_list) {
application = report->application;
if (report->id == td->mt_report_id) {
ret = mt_touch_input_configured(hdev, hi);
rdata = mt_find_report_data(td, report);
if (!rdata) {
hid_err(hdev, "failed to allocate data for report\n");
return -ENOMEM;
}
mt_application = rdata->application;
if (rdata->is_mt_collection) {
ret = mt_touch_input_configured(hdev, hi,
mt_application);
if (ret)
return ret;
}
......@@ -1327,6 +1539,7 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
case HID_GD_SYSTEM_CONTROL:
case HID_CP_CONSUMER_CONTROL:
case HID_GD_WIRELESS_RADIO_CTLS:
case HID_GD_SYSTEM_MULTIAXIS:
/* already handled by hid core */
break;
case HID_DG_TOUCHSCREEN:
......@@ -1390,6 +1603,7 @@ static void mt_fix_const_fields(struct hid_device *hdev, unsigned int usage)
static void mt_release_contacts(struct hid_device *hid)
{
struct hid_input *hidinput;
struct mt_application *application;
struct mt_device *td = hid_get_drvdata(hid);
list_for_each_entry(hidinput, &hid->inputs, list) {
......@@ -1409,7 +1623,9 @@ static void mt_release_contacts(struct hid_device *hid)
}
}
td->num_received = 0;
list_for_each_entry(application, &td->applications, list) {
application->num_received = 0;
}
}
static void mt_expired_timeout(struct timer_list *t)
......@@ -1432,7 +1648,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret, i;
struct mt_device *td;
struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
const struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
for (i = 0; mt_classes[i].name ; i++) {
if (id->driver_data == mt_classes[i].name) {
......@@ -1449,17 +1665,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->hdev = hdev;
td->mtclass = *mtclass;
td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
td->cc_index = -1;
td->scantime_index = -1;
td->mt_report_id = -1;
hid_set_drvdata(hdev, td);
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;
}
INIT_LIST_HEAD(&td->applications);
INIT_LIST_HEAD(&td->reports);
if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
td->serial_maybe = true;
......@@ -1496,10 +1705,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
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;
}
......
......@@ -190,6 +190,12 @@ struct hid_item {
* http://www.usb.org/developers/hidpage/HUTRR40RadioHIDUsagesFinal.pdf
*/
#define HID_GD_WIRELESS_RADIO_CTLS 0x0001000c
/*
* System Multi-Axis, see:
* http://www.usb.org/developers/hidpage/HUTRR62_-_Generic_Desktop_CA_for_System_Multi-Axis_Controllers.txt
*/
#define HID_GD_SYSTEM_MULTIAXIS 0x0001000e
#define HID_GD_X 0x00010030
#define HID_GD_Y 0x00010031
#define HID_GD_Z 0x00010032
......@@ -638,12 +644,13 @@ static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
struct hid_parser {
struct hid_global global;
struct hid_global global_stack[HID_GLOBAL_STACK_SIZE];
unsigned global_stack_ptr;
unsigned int global_stack_ptr;
struct hid_local local;
unsigned collection_stack[HID_COLLECTION_STACK_SIZE];
unsigned collection_stack_ptr;
unsigned int *collection_stack;
unsigned int collection_stack_ptr;
unsigned int collection_stack_size;
struct hid_device *device;
unsigned scan_flags;
unsigned int scan_flags;
};
struct hid_class_descriptor {
......
......@@ -270,10 +270,11 @@ struct input_mask {
/*
* MT_TOOL types
*/
#define MT_TOOL_FINGER 0
#define MT_TOOL_PEN 1
#define MT_TOOL_PALM 2
#define MT_TOOL_MAX 2
#define MT_TOOL_FINGER 0x00
#define MT_TOOL_PEN 0x01
#define MT_TOOL_PALM 0x02
#define MT_TOOL_DIAL 0x0a
#define MT_TOOL_MAX 0x0f
/*
* Values describing the status of a force-feedback effect
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment