diff options
| author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2014-09-23 12:08:09 -0400 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2014-10-01 03:11:23 -0400 |
| commit | 5ae6e89f7409cb5d218bb728326eba9c650d9700 (patch) | |
| tree | e3e1bac35f9c42c6a68666f7a802cf9b654bb607 | |
| parent | 7704ac937345d4b502062952657027234aa86a37 (diff) | |
HID: wacom: implement the finger part of the HID generic handling
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Acked-by: Jason Gerecke <killertofu@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
| -rw-r--r-- | drivers/hid/wacom_sys.c | 39 | ||||
| -rw-r--r-- | drivers/hid/wacom_wac.c | 120 | ||||
| -rw-r--r-- | drivers/hid/wacom_wac.h | 8 |
3 files changed, 164 insertions, 3 deletions
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index dd288b2fbfe8..8593047bb726 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c | |||
| @@ -109,6 +109,7 @@ static void wacom_feature_mapping(struct hid_device *hdev, | |||
| 109 | { | 109 | { |
| 110 | struct wacom *wacom = hid_get_drvdata(hdev); | 110 | struct wacom *wacom = hid_get_drvdata(hdev); |
| 111 | struct wacom_features *features = &wacom->wacom_wac.features; | 111 | struct wacom_features *features = &wacom->wacom_wac.features; |
| 112 | struct hid_data *hid_data = &wacom->wacom_wac.hid_data; | ||
| 112 | u8 *data; | 113 | u8 *data; |
| 113 | int ret; | 114 | int ret; |
| 114 | 115 | ||
| @@ -128,6 +129,16 @@ static void wacom_feature_mapping(struct hid_device *hdev, | |||
| 128 | kfree(data); | 129 | kfree(data); |
| 129 | } | 130 | } |
| 130 | break; | 131 | break; |
| 132 | case HID_DG_INPUTMODE: | ||
| 133 | /* Ignore if value index is out of bounds. */ | ||
| 134 | if (usage->usage_index >= field->report_count) { | ||
| 135 | dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n"); | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | |||
| 139 | hid_data->inputmode = field->report->id; | ||
| 140 | hid_data->inputmode_index = usage->usage_index; | ||
| 141 | break; | ||
| 131 | } | 142 | } |
| 132 | } | 143 | } |
| 133 | 144 | ||
| @@ -255,6 +266,25 @@ static void wacom_parse_hid(struct hid_device *hdev, | |||
| 255 | } | 266 | } |
| 256 | } | 267 | } |
| 257 | 268 | ||
| 269 | static int wacom_hid_set_device_mode(struct hid_device *hdev) | ||
| 270 | { | ||
| 271 | struct wacom *wacom = hid_get_drvdata(hdev); | ||
| 272 | struct hid_data *hid_data = &wacom->wacom_wac.hid_data; | ||
| 273 | struct hid_report *r; | ||
| 274 | struct hid_report_enum *re; | ||
| 275 | |||
| 276 | if (hid_data->inputmode < 0) | ||
| 277 | return 0; | ||
| 278 | |||
| 279 | re = &(hdev->report_enum[HID_FEATURE_REPORT]); | ||
| 280 | r = re->report_id_hash[hid_data->inputmode]; | ||
| 281 | if (r) { | ||
| 282 | r->field[0]->value[hid_data->inputmode_index] = 2; | ||
| 283 | hid_hw_request(hdev, r, HID_REQ_SET_REPORT); | ||
| 284 | } | ||
| 285 | return 0; | ||
| 286 | } | ||
| 287 | |||
| 258 | static int wacom_set_device_mode(struct hid_device *hdev, int report_id, | 288 | static int wacom_set_device_mode(struct hid_device *hdev, int report_id, |
| 259 | int length, int mode) | 289 | int length, int mode) |
| 260 | { | 290 | { |
| @@ -347,6 +377,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev, | |||
| 347 | if (hdev->bus == BUS_BLUETOOTH) | 377 | if (hdev->bus == BUS_BLUETOOTH) |
| 348 | return wacom_bt_query_tablet_data(hdev, 1, features); | 378 | return wacom_bt_query_tablet_data(hdev, 1, features); |
| 349 | 379 | ||
| 380 | if (features->type == HID_GENERIC) | ||
| 381 | return wacom_hid_set_device_mode(hdev); | ||
| 382 | |||
| 350 | if (features->device_type == BTN_TOOL_FINGER) { | 383 | if (features->device_type == BTN_TOOL_FINGER) { |
| 351 | if (features->type > TABLETPC) { | 384 | if (features->type > TABLETPC) { |
| 352 | /* MT Tablet PC touch */ | 385 | /* MT Tablet PC touch */ |
| @@ -1451,9 +1484,6 @@ static int wacom_probe(struct hid_device *hdev, | |||
| 1451 | error); | 1484 | error); |
| 1452 | } | 1485 | } |
| 1453 | 1486 | ||
| 1454 | /* Note that if query fails it is not a hard failure */ | ||
| 1455 | wacom_query_tablet_data(hdev, features); | ||
| 1456 | |||
| 1457 | if (features->type == HID_GENERIC) | 1487 | if (features->type == HID_GENERIC) |
| 1458 | connect_mask |= HID_CONNECT_DRIVER; | 1488 | connect_mask |= HID_CONNECT_DRIVER; |
| 1459 | 1489 | ||
| @@ -1464,6 +1494,9 @@ static int wacom_probe(struct hid_device *hdev, | |||
| 1464 | goto fail_hw_start; | 1494 | goto fail_hw_start; |
| 1465 | } | 1495 | } |
| 1466 | 1496 | ||
| 1497 | /* Note that if query fails it is not a hard failure */ | ||
| 1498 | wacom_query_tablet_data(hdev, features); | ||
| 1499 | |||
| 1467 | if (features->quirks & WACOM_QUIRK_MONITOR) | 1500 | if (features->quirks & WACOM_QUIRK_MONITOR) |
| 1468 | error = hid_hw_open(hdev); | 1501 | error = hid_hw_open(hdev); |
| 1469 | 1502 | ||
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index e77d46d85a11..586b2405b0d4 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c | |||
| @@ -1372,6 +1372,117 @@ static void wacom_wac_pen_report(struct hid_device *hdev, | |||
| 1372 | } | 1372 | } |
| 1373 | } | 1373 | } |
| 1374 | 1374 | ||
| 1375 | static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, | ||
| 1376 | struct hid_field *field, struct hid_usage *usage) | ||
| 1377 | { | ||
| 1378 | struct wacom *wacom = hid_get_drvdata(hdev); | ||
| 1379 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; | ||
| 1380 | struct input_dev *input = wacom_wac->input; | ||
| 1381 | unsigned touch_max = wacom_wac->features.touch_max; | ||
| 1382 | |||
| 1383 | switch (usage->hid) { | ||
| 1384 | case HID_GD_X: | ||
| 1385 | if (touch_max == 1) | ||
| 1386 | wacom_map_usage(wacom, usage, field, EV_ABS, ABS_X, 4); | ||
| 1387 | else | ||
| 1388 | wacom_map_usage(wacom, usage, field, EV_ABS, | ||
| 1389 | ABS_MT_POSITION_X, 4); | ||
| 1390 | break; | ||
| 1391 | case HID_GD_Y: | ||
| 1392 | if (touch_max == 1) | ||
| 1393 | wacom_map_usage(wacom, usage, field, EV_ABS, ABS_Y, 4); | ||
| 1394 | else | ||
| 1395 | wacom_map_usage(wacom, usage, field, EV_ABS, | ||
| 1396 | ABS_MT_POSITION_Y, 4); | ||
| 1397 | break; | ||
| 1398 | case HID_DG_CONTACTID: | ||
| 1399 | input_mt_init_slots(input, wacom_wac->features.touch_max, | ||
| 1400 | INPUT_MT_DIRECT); | ||
| 1401 | break; | ||
| 1402 | case HID_DG_INRANGE: | ||
| 1403 | break; | ||
| 1404 | case HID_DG_INVERT: | ||
| 1405 | break; | ||
| 1406 | case HID_DG_TIPSWITCH: | ||
| 1407 | wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOUCH, 0); | ||
| 1408 | break; | ||
| 1409 | } | ||
| 1410 | } | ||
| 1411 | |||
| 1412 | static int wacom_wac_finger_event(struct hid_device *hdev, | ||
| 1413 | struct hid_field *field, struct hid_usage *usage, __s32 value) | ||
| 1414 | { | ||
| 1415 | struct wacom *wacom = hid_get_drvdata(hdev); | ||
| 1416 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; | ||
| 1417 | |||
| 1418 | switch (usage->hid) { | ||
| 1419 | case HID_GD_X: | ||
| 1420 | wacom_wac->hid_data.x = value; | ||
| 1421 | break; | ||
| 1422 | case HID_GD_Y: | ||
| 1423 | wacom_wac->hid_data.y = value; | ||
| 1424 | break; | ||
| 1425 | case HID_DG_CONTACTID: | ||
| 1426 | wacom_wac->hid_data.id = value; | ||
| 1427 | break; | ||
| 1428 | case HID_DG_TIPSWITCH: | ||
| 1429 | wacom_wac->hid_data.tipswitch = value; | ||
| 1430 | break; | ||
| 1431 | } | ||
| 1432 | |||
| 1433 | |||
| 1434 | return 0; | ||
| 1435 | } | ||
| 1436 | |||
| 1437 | static void wacom_wac_finger_mt_report(struct wacom_wac *wacom_wac, | ||
| 1438 | struct input_dev *input, bool touch) | ||
| 1439 | { | ||
| 1440 | int slot; | ||
| 1441 | struct hid_data *hid_data = &wacom_wac->hid_data; | ||
| 1442 | |||
| 1443 | slot = input_mt_get_slot_by_key(input, hid_data->id); | ||
| 1444 | |||
| 1445 | input_mt_slot(input, slot); | ||
| 1446 | input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); | ||
| 1447 | if (touch) { | ||
| 1448 | input_report_abs(input, ABS_MT_POSITION_X, hid_data->x); | ||
| 1449 | input_report_abs(input, ABS_MT_POSITION_Y, hid_data->y); | ||
| 1450 | } | ||
| 1451 | input_mt_sync_frame(input); | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | static void wacom_wac_finger_single_touch_report(struct wacom_wac *wacom_wac, | ||
| 1455 | struct input_dev *input, bool touch) | ||
| 1456 | { | ||
| 1457 | struct hid_data *hid_data = &wacom_wac->hid_data; | ||
| 1458 | |||
| 1459 | if (touch) { | ||
| 1460 | input_report_abs(input, ABS_X, hid_data->x); | ||
| 1461 | input_report_abs(input, ABS_Y, hid_data->y); | ||
| 1462 | } | ||
| 1463 | input_report_key(input, BTN_TOUCH, touch); | ||
| 1464 | } | ||
| 1465 | |||
| 1466 | static void wacom_wac_finger_report(struct hid_device *hdev, | ||
| 1467 | struct hid_report *report) | ||
| 1468 | { | ||
| 1469 | struct wacom *wacom = hid_get_drvdata(hdev); | ||
| 1470 | struct wacom_wac *wacom_wac = &wacom->wacom_wac; | ||
| 1471 | struct input_dev *input = wacom_wac->input; | ||
| 1472 | bool touch = wacom_wac->hid_data.tipswitch && | ||
| 1473 | !wacom_wac->shared->stylus_in_proximity; | ||
| 1474 | unsigned touch_max = wacom_wac->features.touch_max; | ||
| 1475 | |||
| 1476 | if (touch_max > 1) | ||
| 1477 | wacom_wac_finger_mt_report(wacom_wac, input, touch); | ||
| 1478 | else | ||
| 1479 | wacom_wac_finger_single_touch_report(wacom_wac, input, touch); | ||
| 1480 | input_sync(input); | ||
| 1481 | |||
| 1482 | /* keep touch state for pen event */ | ||
| 1483 | wacom_wac->shared->touch_down = touch; | ||
| 1484 | } | ||
| 1485 | |||
| 1375 | #define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ | 1486 | #define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ |
| 1376 | ((f)->physical == HID_DG_STYLUS)) | 1487 | ((f)->physical == HID_DG_STYLUS)) |
| 1377 | #define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ | 1488 | #define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ |
| @@ -1389,6 +1500,9 @@ void wacom_wac_usage_mapping(struct hid_device *hdev, | |||
| 1389 | 1500 | ||
| 1390 | if (WACOM_PEN_FIELD(field)) | 1501 | if (WACOM_PEN_FIELD(field)) |
| 1391 | return wacom_wac_pen_usage_mapping(hdev, field, usage); | 1502 | return wacom_wac_pen_usage_mapping(hdev, field, usage); |
| 1503 | |||
| 1504 | if (WACOM_FINGER_FIELD(field)) | ||
| 1505 | return wacom_wac_finger_usage_mapping(hdev, field, usage); | ||
| 1392 | } | 1506 | } |
| 1393 | 1507 | ||
| 1394 | int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, | 1508 | int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, |
| @@ -1402,6 +1516,9 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, | |||
| 1402 | if (WACOM_PEN_FIELD(field)) | 1516 | if (WACOM_PEN_FIELD(field)) |
| 1403 | return wacom_wac_pen_event(hdev, field, usage, value); | 1517 | return wacom_wac_pen_event(hdev, field, usage, value); |
| 1404 | 1518 | ||
| 1519 | if (WACOM_FINGER_FIELD(field)) | ||
| 1520 | return wacom_wac_finger_event(hdev, field, usage, value); | ||
| 1521 | |||
| 1405 | return 0; | 1522 | return 0; |
| 1406 | } | 1523 | } |
| 1407 | 1524 | ||
| @@ -1416,6 +1533,9 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) | |||
| 1416 | 1533 | ||
| 1417 | if (WACOM_PEN_FIELD(field)) | 1534 | if (WACOM_PEN_FIELD(field)) |
| 1418 | return wacom_wac_pen_report(hdev, report); | 1535 | return wacom_wac_pen_report(hdev, report); |
| 1536 | |||
| 1537 | if (WACOM_FINGER_FIELD(field)) | ||
| 1538 | return wacom_wac_finger_report(hdev, report); | ||
| 1419 | } | 1539 | } |
| 1420 | 1540 | ||
| 1421 | static int wacom_bpt_touch(struct wacom_wac *wacom) | 1541 | static int wacom_bpt_touch(struct wacom_wac *wacom) |
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index f472eac292d5..0f0b85ec1322 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h | |||
| @@ -156,9 +156,17 @@ struct wacom_shared { | |||
| 156 | }; | 156 | }; |
| 157 | 157 | ||
| 158 | struct hid_data { | 158 | struct hid_data { |
| 159 | __s16 inputmode; /* InputMode HID feature, -1 if non-existent */ | ||
| 160 | __s16 inputmode_index; /* InputMode HID feature index in the report */ | ||
| 159 | bool inrange_state; | 161 | bool inrange_state; |
| 160 | bool invert_state; | 162 | bool invert_state; |
| 161 | bool tipswitch; | 163 | bool tipswitch; |
| 164 | int x; | ||
| 165 | int y; | ||
| 166 | int pressure; | ||
| 167 | int width; | ||
| 168 | int height; | ||
| 169 | int id; | ||
| 162 | }; | 170 | }; |
| 163 | 171 | ||
| 164 | struct wacom_wac { | 172 | struct wacom_wac { |
