diff options
Diffstat (limited to 'drivers/hid/hid-multitouch.c')
-rw-r--r-- | drivers/hid/hid-multitouch.c | 127 |
1 files changed, 70 insertions, 57 deletions
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 3442ed56e964..07d3183fdde5 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -32,8 +32,10 @@ MODULE_LICENSE("GPL"); /* quirks to control the device */ #define MT_QUIRK_NOT_SEEN_MEANS_UP (1 << 0) #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_VALID_IS_INRANGE (1 << 4) +#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5) struct mt_slot { __s32 x, y, p, w, h; @@ -55,6 +57,7 @@ struct mt_device { }; struct mt_class { + __s32 name; /* MT_CLS */ __s32 quirks; __s32 sn_move; /* Signal/noise ratio for move events */ __s32 sn_pressure; /* Signal/noise ratio for pressure events */ @@ -62,26 +65,16 @@ struct mt_class { }; /* 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 * 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) { 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) return i; } - return -1; /* should not occurs. If this happens that means * that the device sent more touches that it says * in the report descriptor. It is ignored then. */ + return -1; } 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, @@ -192,7 +198,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR); field->logical_maximum = 1; - field->logical_minimum = 1; + field->logical_minimum = 0; set_abs(hi->input, ABS_MT_ORIENTATION, field, 0); td->last_slot_field = usage->hid; 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) { - 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); - 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); } @@ -257,16 +263,12 @@ static int mt_compute_slot(struct mt_device *td) */ static void mt_complete_slot(struct mt_device *td) { + td->curdata.seen_in_this_frame = true; if (td->curvalid) { - struct mt_slot *slot; 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++; } @@ -284,21 +286,19 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input) struct mt_slot *s = &(td->slots[i]); if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && !s->seen_in_this_frame) { - /* - * this slot does not contain useful data, - * notify its closure - */ s->touch_state = false; } input_mt_slot(input, i); input_mt_report_slot_state(input, MT_TOOL_FINGER, 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; } @@ -314,16 +314,22 @@ 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); + __s32 quirks = td->mtclass->quirks; if (hid->claimed & HID_CLAIMED_INPUT) { switch (usage->hid) { case HID_DG_INRANGE: + if (quirks & MT_QUIRK_VALID_IS_INRANGE) + td->curvalid = value; break; case HID_DG_TIPSWITCH: - td->curvalid = value; + 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_VALID_IS_CONFIDENCE) + td->curvalid = value; break; case HID_DG_CONTACTID: td->curdata.contactid = value; @@ -345,26 +351,26 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, break; 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) - td->num_expected = value - 1; + td->num_expected = value; break; default: /* fallback to the generic hidinput handling */ 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 */ 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) { - int ret; + int ret, i; 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 * 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; ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); - if (ret != 0) + if (ret) goto fail; mt_set_input_mode(hdev); |