diff options
author | Jason Gerecke <killertofu@gmail.com> | 2014-12-10 19:26:04 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2014-12-11 17:01:56 -0500 |
commit | 601a22f3791473baa2923e4a3125e840279f8bba (patch) | |
tree | 18d6f81096220c62f249345ac1eefe96ba8bb6e2 /drivers/hid | |
parent | b58ba1ba1af9cfbad6f3af4c4fc3575d9aeae542 (diff) |
HID: wacom: Report input events for each finger on generic devices
The existing generic touch code only reports events after reading an
entire HID report, which practically means that only data about the last
contact in a report will ever be provided to userspace. This patch uses
a trick from hid-multitouch.c to discover what type of field is at the
end of each contact; when such a field is encountered all the stored
contact data will be reported.
Signed-off-by: Jason Gerecke <killertofu@gmail.com>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/wacom_wac.c | 86 | ||||
-rw-r--r-- | drivers/hid/wacom_wac.h | 1 |
2 files changed, 59 insertions, 28 deletions
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 064fd6cf36c6..26f27bd6b95c 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c | |||
@@ -1381,10 +1381,12 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, | |||
1381 | { | 1381 | { |
1382 | struct wacom *wacom = hid_get_drvdata(hdev); | 1382 | struct wacom *wacom = hid_get_drvdata(hdev); |
1383 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; | 1383 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; |
1384 | struct wacom_features *features = &wacom_wac->features; | ||
1384 | unsigned touch_max = wacom_wac->features.touch_max; | 1385 | unsigned touch_max = wacom_wac->features.touch_max; |
1385 | 1386 | ||
1386 | switch (usage->hid) { | 1387 | switch (usage->hid) { |
1387 | case HID_GD_X: | 1388 | case HID_GD_X: |
1389 | features->last_slot_field = usage->hid; | ||
1388 | if (touch_max == 1) | 1390 | if (touch_max == 1) |
1389 | wacom_map_usage(wacom, usage, field, EV_ABS, ABS_X, 4); | 1391 | wacom_map_usage(wacom, usage, field, EV_ABS, ABS_X, 4); |
1390 | else | 1392 | else |
@@ -1392,6 +1394,7 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, | |||
1392 | ABS_MT_POSITION_X, 4); | 1394 | ABS_MT_POSITION_X, 4); |
1393 | break; | 1395 | break; |
1394 | case HID_GD_Y: | 1396 | case HID_GD_Y: |
1397 | features->last_slot_field = usage->hid; | ||
1395 | if (touch_max == 1) | 1398 | if (touch_max == 1) |
1396 | wacom_map_usage(wacom, usage, field, EV_ABS, ABS_Y, 4); | 1399 | wacom_map_usage(wacom, usage, field, EV_ABS, ABS_Y, 4); |
1397 | else | 1400 | else |
@@ -1399,17 +1402,48 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, | |||
1399 | ABS_MT_POSITION_Y, 4); | 1402 | ABS_MT_POSITION_Y, 4); |
1400 | break; | 1403 | break; |
1401 | case HID_DG_CONTACTID: | 1404 | case HID_DG_CONTACTID: |
1405 | features->last_slot_field = usage->hid; | ||
1402 | break; | 1406 | break; |
1403 | case HID_DG_INRANGE: | 1407 | case HID_DG_INRANGE: |
1408 | features->last_slot_field = usage->hid; | ||
1404 | break; | 1409 | break; |
1405 | case HID_DG_INVERT: | 1410 | case HID_DG_INVERT: |
1411 | features->last_slot_field = usage->hid; | ||
1406 | break; | 1412 | break; |
1407 | case HID_DG_TIPSWITCH: | 1413 | case HID_DG_TIPSWITCH: |
1414 | features->last_slot_field = usage->hid; | ||
1408 | wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOUCH, 0); | 1415 | wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOUCH, 0); |
1409 | break; | 1416 | break; |
1410 | } | 1417 | } |
1411 | } | 1418 | } |
1412 | 1419 | ||
1420 | static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac, | ||
1421 | struct input_dev *input) | ||
1422 | { | ||
1423 | struct hid_data *hid_data = &wacom_wac->hid_data; | ||
1424 | bool mt = wacom_wac->features.touch_max > 1; | ||
1425 | bool prox = hid_data->tipswitch && | ||
1426 | !wacom_wac->shared->stylus_in_proximity; | ||
1427 | |||
1428 | if (mt) { | ||
1429 | int slot; | ||
1430 | |||
1431 | slot = input_mt_get_slot_by_key(input, hid_data->id); | ||
1432 | input_mt_slot(input, slot); | ||
1433 | input_mt_report_slot_state(input, MT_TOOL_FINGER, prox); | ||
1434 | } | ||
1435 | else { | ||
1436 | input_report_key(input, BTN_TOUCH, prox); | ||
1437 | } | ||
1438 | |||
1439 | if (prox) { | ||
1440 | input_report_abs(input, mt ? ABS_MT_POSITION_X : ABS_X, | ||
1441 | hid_data->x); | ||
1442 | input_report_abs(input, mt ? ABS_MT_POSITION_Y : ABS_Y, | ||
1443 | hid_data->y); | ||
1444 | } | ||
1445 | } | ||
1446 | |||
1413 | static int wacom_wac_finger_event(struct hid_device *hdev, | 1447 | static int wacom_wac_finger_event(struct hid_device *hdev, |
1414 | struct hid_field *field, struct hid_usage *usage, __s32 value) | 1448 | struct hid_field *field, struct hid_usage *usage, __s32 value) |
1415 | { | 1449 | { |
@@ -1432,36 +1466,35 @@ static int wacom_wac_finger_event(struct hid_device *hdev, | |||
1432 | } | 1466 | } |
1433 | 1467 | ||
1434 | 1468 | ||
1469 | if (usage->usage_index + 1 == field->report_count) { | ||
1470 | if (usage->hid == wacom_wac->features.last_slot_field) | ||
1471 | wacom_wac_finger_slot(wacom_wac, wacom_wac->input); | ||
1472 | } | ||
1473 | |||
1435 | return 0; | 1474 | return 0; |
1436 | } | 1475 | } |
1437 | 1476 | ||
1438 | static void wacom_wac_finger_mt_report(struct wacom_wac *wacom_wac, | 1477 | static int wacom_wac_finger_count_touches(struct hid_device *hdev) |
1439 | struct input_dev *input, bool touch) | ||
1440 | { | 1478 | { |
1441 | int slot; | 1479 | struct wacom *wacom = hid_get_drvdata(hdev); |
1442 | struct hid_data *hid_data = &wacom_wac->hid_data; | 1480 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; |
1481 | struct input_dev *input = wacom_wac->input; | ||
1482 | unsigned touch_max = wacom_wac->features.touch_max; | ||
1483 | int count = 0; | ||
1484 | int i; | ||
1443 | 1485 | ||
1444 | slot = input_mt_get_slot_by_key(input, hid_data->id); | 1486 | if (touch_max == 1) |
1487 | return wacom_wac->hid_data.tipswitch && | ||
1488 | !wacom_wac->shared->stylus_in_proximity; | ||
1445 | 1489 | ||
1446 | input_mt_slot(input, slot); | 1490 | for (i = 0; i < input->mt->num_slots; i++) { |
1447 | input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); | 1491 | struct input_mt_slot *ps = &input->mt->slots[i]; |
1448 | if (touch) { | 1492 | int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID); |
1449 | input_report_abs(input, ABS_MT_POSITION_X, hid_data->x); | 1493 | if (id >= 0) |
1450 | input_report_abs(input, ABS_MT_POSITION_Y, hid_data->y); | 1494 | count++; |
1451 | } | 1495 | } |
1452 | input_mt_sync_frame(input); | ||
1453 | } | ||
1454 | |||
1455 | static void wacom_wac_finger_single_touch_report(struct wacom_wac *wacom_wac, | ||
1456 | struct input_dev *input, bool touch) | ||
1457 | { | ||
1458 | struct hid_data *hid_data = &wacom_wac->hid_data; | ||
1459 | 1496 | ||
1460 | if (touch) { | 1497 | return count; |
1461 | input_report_abs(input, ABS_X, hid_data->x); | ||
1462 | input_report_abs(input, ABS_Y, hid_data->y); | ||
1463 | } | ||
1464 | input_report_key(input, BTN_TOUCH, touch); | ||
1465 | } | 1498 | } |
1466 | 1499 | ||
1467 | static void wacom_wac_finger_report(struct hid_device *hdev, | 1500 | static void wacom_wac_finger_report(struct hid_device *hdev, |
@@ -1470,18 +1503,15 @@ static void wacom_wac_finger_report(struct hid_device *hdev, | |||
1470 | struct wacom *wacom = hid_get_drvdata(hdev); | 1503 | struct wacom *wacom = hid_get_drvdata(hdev); |
1471 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; | 1504 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; |
1472 | struct input_dev *input = wacom_wac->input; | 1505 | struct input_dev *input = wacom_wac->input; |
1473 | bool touch = wacom_wac->hid_data.tipswitch && | ||
1474 | !wacom_wac->shared->stylus_in_proximity; | ||
1475 | unsigned touch_max = wacom_wac->features.touch_max; | 1506 | unsigned touch_max = wacom_wac->features.touch_max; |
1476 | 1507 | ||
1477 | if (touch_max > 1) | 1508 | if (touch_max > 1) |
1478 | wacom_wac_finger_mt_report(wacom_wac, input, touch); | 1509 | input_mt_sync_frame(input); |
1479 | else | 1510 | |
1480 | wacom_wac_finger_single_touch_report(wacom_wac, input, touch); | ||
1481 | input_sync(input); | 1511 | input_sync(input); |
1482 | 1512 | ||
1483 | /* keep touch state for pen event */ | 1513 | /* keep touch state for pen event */ |
1484 | wacom_wac->shared->touch_down = touch; | 1514 | wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(hdev); |
1485 | } | 1515 | } |
1486 | 1516 | ||
1487 | #define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ | 1517 | #define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ |
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 5384043778fc..bfad815cda8a 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h | |||
@@ -145,6 +145,7 @@ struct wacom_features { | |||
145 | int pktlen; | 145 | int pktlen; |
146 | bool check_for_hid_type; | 146 | bool check_for_hid_type; |
147 | int hid_type; | 147 | int hid_type; |
148 | int last_slot_field; | ||
148 | }; | 149 | }; |
149 | 150 | ||
150 | struct wacom_shared { | 151 | struct wacom_shared { |