|
|
@@ -85,11 +85,12 @@ MODULE_LICENSE("GPL");
|
|
|
#define MT_IO_FLAGS_PENDING_SLOTS 2
|
|
|
|
|
|
struct mt_slot {
|
|
|
- __s32 x, y, cx, cy, p, w, h;
|
|
|
+ __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 */
|
|
|
};
|
|
|
|
|
|
struct mt_class {
|
|
|
@@ -119,6 +120,10 @@ struct mt_device {
|
|
|
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 */
|
|
|
unsigned long initial_quirks; /* initial quirks state */
|
|
|
@@ -582,8 +587,15 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
|
if (!(cls->quirks & MT_QUIRK_NO_AREA)) {
|
|
|
set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
|
|
|
cls->sn_height);
|
|
|
- input_set_abs_params(hi->input,
|
|
|
- ABS_MT_ORIENTATION, 0, 1, 0, 0);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Only set ABS_MT_ORIENTATION if it is not
|
|
|
+ * already set by the HID_DG_AZIMUTH usage.
|
|
|
+ */
|
|
|
+ if (!test_bit(ABS_MT_ORIENTATION,
|
|
|
+ hi->input->absbit))
|
|
|
+ input_set_abs_params(hi->input,
|
|
|
+ ABS_MT_ORIENTATION, 0, 1, 0, 0);
|
|
|
}
|
|
|
mt_store_field(usage, td, hi);
|
|
|
return 1;
|
|
|
@@ -599,6 +611,12 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
|
EV_MSC, MSC_TIMESTAMP);
|
|
|
input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP);
|
|
|
mt_store_field(usage, td, hi);
|
|
|
+ /* 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;
|
|
|
return 1;
|
|
|
case HID_DG_CONTACTCOUNT:
|
|
|
/* Ignore if indexes are out of bounds. */
|
|
|
@@ -608,6 +626,21 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
|
td->cc_index = field->index;
|
|
|
td->cc_value_index = 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
|
|
|
+ * MAX according the definition of ABS_MT_ORIENTATION
|
|
|
+ */
|
|
|
+ input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
|
|
|
+ -field->logical_maximum / 4,
|
|
|
+ field->logical_maximum / 4,
|
|
|
+ cls->sn_move ?
|
|
|
+ field->logical_maximum / cls->sn_move : 0, 0);
|
|
|
+ mt_store_field(usage, td, hi);
|
|
|
+ return 1;
|
|
|
case HID_DG_CONTACTMAX:
|
|
|
/* we don't set td->last_slot_field as contactcount and
|
|
|
* contact max are global to the report */
|
|
|
@@ -700,6 +733,10 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
|
|
|
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
|
|
|
@@ -716,7 +753,8 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
|
|
|
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, wide);
|
|
|
+ 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);
|
|
|
@@ -734,10 +772,16 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
|
|
|
*/
|
|
|
static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
|
|
|
{
|
|
|
+ __s32 cls = td->mtclass.name;
|
|
|
+
|
|
|
+ if (cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL)
|
|
|
+ input_event(input, EV_KEY, BTN_LEFT, td->left_button_state);
|
|
|
+
|
|
|
input_mt_sync_frame(input);
|
|
|
input_event(input, EV_MSC, MSC_TIMESTAMP, td->timestamp);
|
|
|
input_sync(input);
|
|
|
td->num_received = 0;
|
|
|
+ td->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
|
|
|
@@ -778,9 +822,11 @@ static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
|
|
|
}
|
|
|
|
|
|
static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
|
|
|
- struct hid_usage *usage, __s32 value)
|
|
|
+ struct hid_usage *usage, __s32 value,
|
|
|
+ bool first_packet)
|
|
|
{
|
|
|
struct mt_device *td = hid_get_drvdata(hid);
|
|
|
+ __s32 cls = td->mtclass.name;
|
|
|
__s32 quirks = td->mtclass.quirks;
|
|
|
struct input_dev *input = field->hidinput->input;
|
|
|
|
|
|
@@ -832,11 +878,49 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
|
|
|
break;
|
|
|
case HID_DG_CONTACTCOUNT:
|
|
|
break;
|
|
|
+ case HID_DG_AZIMUTH:
|
|
|
+ /*
|
|
|
+ * Azimuth is counter-clockwise and ranges from [0, MAX)
|
|
|
+ * (a full revolution). Convert it to clockwise ranging
|
|
|
+ * [-MAX/2, MAX/2].
|
|
|
+ *
|
|
|
+ * Note that ABS_MT_ORIENTATION require us to report
|
|
|
+ * the limit of [-MAX/4, MAX/4], but the value can go
|
|
|
+ * 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;
|
|
|
|
|
|
default:
|
|
|
+ /*
|
|
|
+ * For Win8 PTP touchpads we should only look at
|
|
|
+ * non finger/touch events in the first_packet of
|
|
|
+ * a (possible) multi-packet frame.
|
|
|
+ */
|
|
|
+ if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) &&
|
|
|
+ !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 ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) &&
|
|
|
+ usage->type == EV_KEY && usage->code == BTN_LEFT) {
|
|
|
+ td->left_button_state |= value;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
if (usage->type)
|
|
|
input_event(input, usage->type, usage->code,
|
|
|
value);
|
|
|
@@ -855,9 +939,11 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
|
|
|
static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
|
|
|
{
|
|
|
struct mt_device *td = hid_get_drvdata(hid);
|
|
|
+ __s32 cls = td->mtclass.name;
|
|
|
struct hid_field *field;
|
|
|
+ bool first_packet;
|
|
|
unsigned count;
|
|
|
- int r, n;
|
|
|
+ int r, n, scantime = 0;
|
|
|
|
|
|
/* sticky fingers release in progress, abort */
|
|
|
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
|
|
|
@@ -867,13 +953,31 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
|
|
|
* 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 (value)
|
|
|
+
|
|
|
+ /*
|
|
|
+ * For Win8 PTPs the first packet (td->num_received == 0) may
|
|
|
+ * have a contactcount of 0 if there only is a button event.
|
|
|
+ * We double check that this is not a continuation packet
|
|
|
+ * of a possible multi-packet frame be checking that the
|
|
|
+ * timestamp has changed.
|
|
|
+ */
|
|
|
+ if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) &&
|
|
|
+ td->num_received == 0 && td->prev_scantime != scantime)
|
|
|
+ td->num_expected = value;
|
|
|
+ /* A non 0 contact count always indicates a first packet */
|
|
|
+ else if (value)
|
|
|
td->num_expected = value;
|
|
|
}
|
|
|
+ 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;
|
|
|
@@ -883,7 +987,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
|
|
|
|
|
|
for (n = 0; n < count; n++)
|
|
|
mt_process_mt_event(hid, field, &field->usage[n],
|
|
|
- field->value[n]);
|
|
|
+ field->value[n], first_packet);
|
|
|
}
|
|
|
|
|
|
if (td->num_received >= td->num_expected)
|
|
|
@@ -1329,6 +1433,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|
|
td->maxcontact_report_id = -1;
|
|
|
td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
|
|
|
td->cc_index = -1;
|
|
|
+ td->scantime_index = -1;
|
|
|
td->mt_report_id = -1;
|
|
|
hid_set_drvdata(hdev, td);
|
|
|
|
|
|
@@ -1649,14 +1754,6 @@ static const struct hid_device_id mt_devices[] = {
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,
|
|
|
USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
|
|
|
|
|
|
- /* Panasonic panels */
|
|
|
- { .driver_data = MT_CLS_PANASONIC,
|
|
|
- MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
|
|
|
- USB_DEVICE_ID_PANABOARD_UBT780) },
|
|
|
- { .driver_data = MT_CLS_PANASONIC,
|
|
|
- MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
|
|
|
- USB_DEVICE_ID_PANABOARD_UBT880) },
|
|
|
-
|
|
|
/* Novatek Panel */
|
|
|
{ .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK,
|
|
|
@@ -1667,6 +1764,14 @@ static const struct hid_device_id mt_devices[] = {
|
|
|
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
|
|
|
USB_VENDOR_ID_NTRIG, 0x1b05) },
|
|
|
|
|
|
+ /* Panasonic panels */
|
|
|
+ { .driver_data = MT_CLS_PANASONIC,
|
|
|
+ MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
|
|
|
+ USB_DEVICE_ID_PANABOARD_UBT780) },
|
|
|
+ { .driver_data = MT_CLS_PANASONIC,
|
|
|
+ MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
|
|
|
+ USB_DEVICE_ID_PANABOARD_UBT880) },
|
|
|
+
|
|
|
/* PixArt optical touch screen */
|
|
|
{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
|