|
@@ -32,8 +32,10 @@ MODULE_LICENSE("GPL");
|
|
/* quirks to control the device */
|
|
/* quirks to control the device */
|
|
#define MT_QUIRK_NOT_SEEN_MEANS_UP (1 << 0)
|
|
#define MT_QUIRK_NOT_SEEN_MEANS_UP (1 << 0)
|
|
#define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1)
|
|
#define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1)
|
|
-#define MT_QUIRK_CYPRESS (1 << 2)
|
|
|
|
|
|
+#define MT_QUIRK_CYPRESS (1 << 2)
|
|
#define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3)
|
|
#define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3)
|
|
|
|
+#define MT_QUIRK_VALID_IS_INRANGE (1 << 4)
|
|
|
|
+#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5)
|
|
|
|
|
|
struct mt_slot {
|
|
struct mt_slot {
|
|
__s32 x, y, p, w, h;
|
|
__s32 x, y, p, w, h;
|
|
@@ -55,6 +57,7 @@ struct mt_device {
|
|
};
|
|
};
|
|
|
|
|
|
struct mt_class {
|
|
struct mt_class {
|
|
|
|
+ __s32 name; /* MT_CLS */
|
|
__s32 quirks;
|
|
__s32 quirks;
|
|
__s32 sn_move; /* Signal/noise ratio for move events */
|
|
__s32 sn_move; /* Signal/noise ratio for move events */
|
|
__s32 sn_pressure; /* Signal/noise ratio for pressure events */
|
|
__s32 sn_pressure; /* Signal/noise ratio for pressure events */
|
|
@@ -62,26 +65,16 @@ struct mt_class {
|
|
};
|
|
};
|
|
|
|
|
|
/* classes of device behavior */
|
|
/* classes of device behavior */
|
|
-#define MT_CLS_DEFAULT 0
|
|
|
|
-#define MT_CLS_DUAL1 1
|
|
|
|
-#define MT_CLS_DUAL2 2
|
|
|
|
-#define MT_CLS_CYPRESS 3
|
|
|
|
|
|
+#define MT_CLS_DEFAULT 1
|
|
|
|
+#define MT_CLS_DUAL1 2
|
|
|
|
+#define MT_CLS_DUAL2 3
|
|
|
|
+#define MT_CLS_CYPRESS 4
|
|
|
|
|
|
/*
|
|
/*
|
|
* these device-dependent functions determine what slot corresponds
|
|
* these device-dependent functions determine what slot corresponds
|
|
* to a valid contact that was just read.
|
|
* to a valid contact that was just read.
|
|
*/
|
|
*/
|
|
|
|
|
|
-static int slot_is_contactid(struct mt_device *td)
|
|
|
|
-{
|
|
|
|
- return td->curdata.contactid;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int slot_is_contactnumber(struct mt_device *td)
|
|
|
|
-{
|
|
|
|
- return td->num_received;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int cypress_compute_slot(struct mt_device *td)
|
|
static int cypress_compute_slot(struct mt_device *td)
|
|
{
|
|
{
|
|
if (td->curdata.contactid != 0 || td->num_received == 0)
|
|
if (td->curdata.contactid != 0 || td->num_received == 0)
|
|
@@ -103,17 +96,30 @@ static int find_slot_from_contactid(struct mt_device *td)
|
|
!td->slots[i].touch_state)
|
|
!td->slots[i].touch_state)
|
|
return i;
|
|
return i;
|
|
}
|
|
}
|
|
- return -1;
|
|
|
|
/* should not occurs. If this happens that means
|
|
/* should not occurs. If this happens that means
|
|
* that the device sent more touches that it says
|
|
* that the device sent more touches that it says
|
|
* in the report descriptor. It is ignored then. */
|
|
* in the report descriptor. It is ignored then. */
|
|
|
|
+ return -1;
|
|
}
|
|
}
|
|
|
|
|
|
struct mt_class mt_classes[] = {
|
|
struct mt_class mt_classes[] = {
|
|
- { 0, 0, 0, 10 }, /* MT_CLS_DEFAULT */
|
|
|
|
- { MT_QUIRK_SLOT_IS_CONTACTID, 0, 0, 2 }, /* MT_CLS_DUAL1 */
|
|
|
|
- { MT_QUIRK_SLOT_IS_CONTACTNUMBER, 0, 0, 10 }, /* MT_CLS_DUAL2 */
|
|
|
|
- { MT_QUIRK_CYPRESS | MT_QUIRK_NOT_SEEN_MEANS_UP, 0, 0, 10 }, /* MT_CLS_CYPRESS */
|
|
|
|
|
|
+ { .name = MT_CLS_DEFAULT,
|
|
|
|
+ .quirks = MT_QUIRK_VALID_IS_INRANGE,
|
|
|
|
+ .maxcontacts = 10 },
|
|
|
|
+ { .name = MT_CLS_DUAL1,
|
|
|
|
+ .quirks = MT_QUIRK_VALID_IS_INRANGE |
|
|
|
|
+ MT_QUIRK_SLOT_IS_CONTACTID,
|
|
|
|
+ .maxcontacts = 2 },
|
|
|
|
+ { .name = MT_CLS_DUAL2,
|
|
|
|
+ .quirks = MT_QUIRK_VALID_IS_INRANGE |
|
|
|
|
+ MT_QUIRK_SLOT_IS_CONTACTNUMBER,
|
|
|
|
+ .maxcontacts = 2 },
|
|
|
|
+ { .name = MT_CLS_CYPRESS,
|
|
|
|
+ .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
|
|
|
|
+ MT_QUIRK_CYPRESS,
|
|
|
|
+ .maxcontacts = 10 },
|
|
|
|
+
|
|
|
|
+ { }
|
|
};
|
|
};
|
|
|
|
|
|
static void mt_feature_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
static void mt_feature_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
@@ -192,7 +198,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
hid_map_usage(hi, usage, bit, max,
|
|
hid_map_usage(hi, usage, bit, max,
|
|
EV_ABS, ABS_MT_TOUCH_MINOR);
|
|
EV_ABS, ABS_MT_TOUCH_MINOR);
|
|
field->logical_maximum = 1;
|
|
field->logical_maximum = 1;
|
|
- field->logical_minimum = 1;
|
|
|
|
|
|
+ field->logical_minimum = 0;
|
|
set_abs(hi->input, ABS_MT_ORIENTATION, field, 0);
|
|
set_abs(hi->input, ABS_MT_ORIENTATION, field, 0);
|
|
td->last_slot_field = usage->hid;
|
|
td->last_slot_field = usage->hid;
|
|
return 1;
|
|
return 1;
|
|
@@ -237,16 +243,16 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
|
|
|
|
|
|
static int mt_compute_slot(struct mt_device *td)
|
|
static int mt_compute_slot(struct mt_device *td)
|
|
{
|
|
{
|
|
- struct mt_class *cls = td->mtclass;
|
|
|
|
|
|
+ __s32 quirks = td->mtclass->quirks;
|
|
|
|
|
|
- if (cls->quirks & MT_QUIRK_SLOT_IS_CONTACTID)
|
|
|
|
- return slot_is_contactid(td);
|
|
|
|
|
|
+ if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
|
|
|
|
+ return td->curdata.contactid;
|
|
|
|
|
|
- if (cls->quirks & MT_QUIRK_CYPRESS)
|
|
|
|
|
|
+ if (quirks & MT_QUIRK_CYPRESS)
|
|
return cypress_compute_slot(td);
|
|
return cypress_compute_slot(td);
|
|
|
|
|
|
- if (cls->quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
|
|
|
|
- return slot_is_contactnumber(td);
|
|
|
|
|
|
+ if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
|
|
|
|
+ return td->num_received;
|
|
|
|
|
|
return find_slot_from_contactid(td);
|
|
return find_slot_from_contactid(td);
|
|
}
|
|
}
|
|
@@ -257,16 +263,12 @@ static int mt_compute_slot(struct mt_device *td)
|
|
*/
|
|
*/
|
|
static void mt_complete_slot(struct mt_device *td)
|
|
static void mt_complete_slot(struct mt_device *td)
|
|
{
|
|
{
|
|
|
|
+ td->curdata.seen_in_this_frame = true;
|
|
if (td->curvalid) {
|
|
if (td->curvalid) {
|
|
- struct mt_slot *slot;
|
|
|
|
int slotnum = mt_compute_slot(td);
|
|
int slotnum = mt_compute_slot(td);
|
|
|
|
|
|
- if (slotnum >= 0 && slotnum < td->mtclass->maxcontacts) {
|
|
|
|
- slot = td->slots + slotnum;
|
|
|
|
-
|
|
|
|
- memcpy(slot, &(td->curdata), sizeof(struct mt_slot));
|
|
|
|
- slot->seen_in_this_frame = true;
|
|
|
|
- }
|
|
|
|
|
|
+ if (slotnum >= 0 && slotnum < td->mtclass->maxcontacts)
|
|
|
|
+ td->slots[slotnum] = td->curdata;
|
|
}
|
|
}
|
|
td->num_received++;
|
|
td->num_received++;
|
|
}
|
|
}
|
|
@@ -284,21 +286,19 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input)
|
|
struct mt_slot *s = &(td->slots[i]);
|
|
struct mt_slot *s = &(td->slots[i]);
|
|
if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) &&
|
|
if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) &&
|
|
!s->seen_in_this_frame) {
|
|
!s->seen_in_this_frame) {
|
|
- /*
|
|
|
|
- * this slot does not contain useful data,
|
|
|
|
- * notify its closure
|
|
|
|
- */
|
|
|
|
s->touch_state = false;
|
|
s->touch_state = false;
|
|
}
|
|
}
|
|
|
|
|
|
input_mt_slot(input, i);
|
|
input_mt_slot(input, i);
|
|
input_mt_report_slot_state(input, MT_TOOL_FINGER,
|
|
input_mt_report_slot_state(input, MT_TOOL_FINGER,
|
|
s->touch_state);
|
|
s->touch_state);
|
|
- 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_PRESSURE, s->p);
|
|
|
|
- input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, s->w);
|
|
|
|
- input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, s->h);
|
|
|
|
|
|
+ if (s->touch_state) {
|
|
|
|
+ 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_PRESSURE, s->p);
|
|
|
|
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, s->w);
|
|
|
|
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, s->h);
|
|
|
|
+ }
|
|
s->seen_in_this_frame = false;
|
|
s->seen_in_this_frame = false;
|
|
|
|
|
|
}
|
|
}
|
|
@@ -314,16 +314,22 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
|
|
struct hid_usage *usage, __s32 value)
|
|
struct hid_usage *usage, __s32 value)
|
|
{
|
|
{
|
|
struct mt_device *td = hid_get_drvdata(hid);
|
|
struct mt_device *td = hid_get_drvdata(hid);
|
|
|
|
+ __s32 quirks = td->mtclass->quirks;
|
|
|
|
|
|
if (hid->claimed & HID_CLAIMED_INPUT) {
|
|
if (hid->claimed & HID_CLAIMED_INPUT) {
|
|
switch (usage->hid) {
|
|
switch (usage->hid) {
|
|
case HID_DG_INRANGE:
|
|
case HID_DG_INRANGE:
|
|
|
|
+ if (quirks & MT_QUIRK_VALID_IS_INRANGE)
|
|
|
|
+ td->curvalid = value;
|
|
break;
|
|
break;
|
|
case HID_DG_TIPSWITCH:
|
|
case HID_DG_TIPSWITCH:
|
|
- td->curvalid = value;
|
|
|
|
|
|
+ if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
|
|
|
|
+ td->curvalid = value;
|
|
td->curdata.touch_state = value;
|
|
td->curdata.touch_state = value;
|
|
break;
|
|
break;
|
|
case HID_DG_CONFIDENCE:
|
|
case HID_DG_CONFIDENCE:
|
|
|
|
+ if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
|
|
|
|
+ td->curvalid = value;
|
|
break;
|
|
break;
|
|
case HID_DG_CONTACTID:
|
|
case HID_DG_CONTACTID:
|
|
td->curdata.contactid = value;
|
|
td->curdata.contactid = value;
|
|
@@ -345,26 +351,26 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
|
|
break;
|
|
break;
|
|
case HID_DG_CONTACTCOUNT:
|
|
case HID_DG_CONTACTCOUNT:
|
|
/*
|
|
/*
|
|
- * We must not overwrite the previous value (some
|
|
|
|
- * devices send one sequence splitted over several
|
|
|
|
- * messages)
|
|
|
|
|
|
+ * Includes multi-packet support where subsequent
|
|
|
|
+ * packets are sent with zero contactcount.
|
|
*/
|
|
*/
|
|
if (value)
|
|
if (value)
|
|
- td->num_expected = value - 1;
|
|
|
|
|
|
+ td->num_expected = value;
|
|
break;
|
|
break;
|
|
|
|
|
|
default:
|
|
default:
|
|
/* fallback to the generic hidinput handling */
|
|
/* fallback to the generic hidinput handling */
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
|
|
- if (usage->hid == td->last_slot_field)
|
|
|
|
- mt_complete_slot(td);
|
|
|
|
|
|
+ if (usage->hid == td->last_slot_field)
|
|
|
|
+ mt_complete_slot(td);
|
|
|
|
+
|
|
|
|
+ if (field->index == td->last_field_index
|
|
|
|
+ && td->num_received >= td->num_expected)
|
|
|
|
+ mt_emit_event(td, field->hidinput->input);
|
|
|
|
|
|
- if (field->index == td->last_field_index
|
|
|
|
- && td->num_received > td->num_expected)
|
|
|
|
- mt_emit_event(td, field->hidinput->input);
|
|
|
|
|
|
+ }
|
|
|
|
|
|
/* we have handled the hidinput part, now remains hiddev */
|
|
/* we have handled the hidinput part, now remains hiddev */
|
|
if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
|
|
if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
|
|
@@ -392,9 +398,16 @@ static void mt_set_input_mode(struct hid_device *hdev)
|
|
|
|
|
|
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|
{
|
|
{
|
|
- int ret;
|
|
|
|
|
|
+ int ret, i;
|
|
struct mt_device *td;
|
|
struct mt_device *td;
|
|
- struct mt_class *mtclass = mt_classes + id->driver_data;
|
|
|
|
|
|
+ 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) {
|
|
|
|
+ mtclass = &(mt_classes[i]);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
/* This allows the driver to correctly support devices
|
|
/* This allows the driver to correctly support devices
|
|
* that emit events over several HID messages.
|
|
* that emit events over several HID messages.
|
|
@@ -417,7 +430,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|
goto fail;
|
|
goto fail;
|
|
|
|
|
|
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
|
|
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
|
|
- if (ret != 0)
|
|
|
|
|
|
+ if (ret)
|
|
goto fail;
|
|
goto fail;
|
|
|
|
|
|
mt_set_input_mode(hdev);
|
|
mt_set_input_mode(hdev);
|