diff options
author | Frank Praznik <frank.praznik@oh.rr.com> | 2014-01-27 10:17:37 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2014-01-28 14:37:45 -0500 |
commit | e560623050693d2550d0bfb3b092e6398249176e (patch) | |
tree | 8f9f928ba3872984de871187e578041addb877d6 /drivers/hid/hid-sony.c | |
parent | d902f4724ccd0c6b8f2b0a7d22af428c637b6dda (diff) |
HID: sony: add output events for the multi-touch pad on the Dualshock 4
Add output events for the multi-touch pad on the Dualshock 4.
The touchpad has a resolution of 1920x940 and is capable of 2 simultaneous
touches. A 'Type B' stateful slot protocol is implemented as defined in
Documentation/input/multi-touch-protocol.txt
Applications can use the touchpad data by processing the ABS_MT_SLOT,
ABS_MT_TRACKING_ID, ABS_MT_POSITION_X and ABS_MT_POSITION_Y events.
Signed-off-by: Frank Praznik <frank.praznik@oh.rr.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-sony.c')
-rw-r--r-- | drivers/hid/hid-sony.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 04fd611d3099..2bd3f130be20 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/leds.h> | 32 | #include <linux/leds.h> |
33 | #include <linux/power_supply.h> | 33 | #include <linux/power_supply.h> |
34 | #include <linux/spinlock.h> | 34 | #include <linux/spinlock.h> |
35 | #include <linux/input/mt.h> | ||
35 | 36 | ||
36 | #include "hid-ids.h" | 37 | #include "hid-ids.h" |
37 | 38 | ||
@@ -643,7 +644,11 @@ static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size) | |||
643 | 644 | ||
644 | static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size) | 645 | static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size) |
645 | { | 646 | { |
647 | struct hid_input *hidinput = list_entry(sc->hdev->inputs.next, | ||
648 | struct hid_input, list); | ||
649 | struct input_dev *input_dev = hidinput->input; | ||
646 | unsigned long flags; | 650 | unsigned long flags; |
651 | int n, offset = 35; | ||
647 | __u8 cable_state, battery_capacity, battery_charging; | 652 | __u8 cable_state, battery_capacity, battery_charging; |
648 | 653 | ||
649 | /* The lower 4 bits of byte 30 contain the battery level | 654 | /* The lower 4 bits of byte 30 contain the battery level |
@@ -669,6 +674,28 @@ static void dualshock4_parse_report(struct sony_sc *sc, __u8 *rd, int size) | |||
669 | sc->battery_capacity = battery_capacity; | 674 | sc->battery_capacity = battery_capacity; |
670 | sc->battery_charging = battery_charging; | 675 | sc->battery_charging = battery_charging; |
671 | spin_unlock_irqrestore(&sc->lock, flags); | 676 | spin_unlock_irqrestore(&sc->lock, flags); |
677 | |||
678 | /* The Dualshock 4 multi-touch trackpad data starts at offset 35 on USB. | ||
679 | * The first 7 bits of the first byte is a counter and bit 8 is a touch | ||
680 | * indicator that is 0 when pressed and 1 when not pressed. | ||
681 | * The next 3 bytes are two 12 bit touch coordinates, X and Y. | ||
682 | * The data for the second touch is in the same format and immediatly | ||
683 | * follows the data for the first. | ||
684 | */ | ||
685 | for (n = 0; n < 2; n++) { | ||
686 | __u16 x, y; | ||
687 | |||
688 | x = rd[offset+1] | ((rd[offset+2] & 0xF) << 8); | ||
689 | y = ((rd[offset+2] & 0xF0) >> 4) | (rd[offset+3] << 4); | ||
690 | |||
691 | input_mt_slot(input_dev, n); | ||
692 | input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, | ||
693 | !(rd[offset] >> 7)); | ||
694 | input_report_abs(input_dev, ABS_MT_POSITION_X, x); | ||
695 | input_report_abs(input_dev, ABS_MT_POSITION_Y, y); | ||
696 | |||
697 | offset += 4; | ||
698 | } | ||
672 | } | 699 | } |
673 | 700 | ||
674 | static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, | 701 | static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, |
@@ -1200,6 +1227,26 @@ static int sony_set_output_report(struct sony_sc *sc, int req_id, int req_size) | |||
1200 | return -EINVAL; | 1227 | return -EINVAL; |
1201 | } | 1228 | } |
1202 | 1229 | ||
1230 | static int sony_register_touchpad(struct sony_sc *sc, int touch_count, | ||
1231 | int w, int h) | ||
1232 | { | ||
1233 | struct hid_input *hidinput = list_entry(sc->hdev->inputs.next, | ||
1234 | struct hid_input, list); | ||
1235 | struct input_dev *input_dev = hidinput->input; | ||
1236 | int ret; | ||
1237 | |||
1238 | ret = input_mt_init_slots(input_dev, touch_count, 0); | ||
1239 | if (ret < 0) { | ||
1240 | hid_err(sc->hdev, "Unable to initialize multi-touch slots\n"); | ||
1241 | return ret; | ||
1242 | } | ||
1243 | |||
1244 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, w, 0, 0); | ||
1245 | input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, h, 0, 0); | ||
1246 | |||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
1203 | static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) | 1250 | static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) |
1204 | { | 1251 | { |
1205 | int ret; | 1252 | int ret; |
@@ -1249,6 +1296,13 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
1249 | if (ret < 0) | 1296 | if (ret < 0) |
1250 | goto err_stop; | 1297 | goto err_stop; |
1251 | 1298 | ||
1299 | /* The Dualshock 4 touchpad supports 2 touches and has a | ||
1300 | * resolution of 1920x940. | ||
1301 | */ | ||
1302 | ret = sony_register_touchpad(sc, 2, 1920, 940); | ||
1303 | if (ret < 0) | ||
1304 | goto err_stop; | ||
1305 | |||
1252 | INIT_WORK(&sc->state_worker, dualshock4_state_worker); | 1306 | INIT_WORK(&sc->state_worker, dualshock4_state_worker); |
1253 | } else { | 1307 | } else { |
1254 | ret = 0; | 1308 | ret = 0; |