summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
authorRoderick Colenbrander <roderick.colenbrander@sony.com>2016-11-23 14:07:08 -0800
committerSiarhei Vishniakou <svv@google.com>2019-11-07 11:13:35 -0600
commit7ec96e9f0cf95ffadff651ff539c076c94bcfc73 (patch)
tree6bdba6d655703476248153b8271d0148cb42f3ba /drivers/hid
parentaa388599ce27d29d9d697698fe4ad0ba8ca03e61 (diff)
UPSTREAM: HID: sony: Comply to Linux gamepad spec for DS4
The DS4 side of hid-sony used the hid-core layer to assign buttons and axes based on the HID report descriptors. The default mapping was strange e.g. right stick using ABS_Z/ABS_RZ or the physical 'south button' being reported as BTN_EAST etcetera. This patch makes the DS4 side ofi the hid-sony driver comply to the Linux game controller spec as suggested in a discussion with Dmitry on the linux-input list. Currently the main user of the DS4 is the SDL2 library, which has a mapping table using vendor/device/version as a key. In order to not break SDL2 we discussed adjusting the version number, so it can have both mappings. This was discust on linux-input and we discussed privately with SDL2 developers. Signed-off-by: Roderick Colenbrander <roderick.colenbrander@sony.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz> (cherry picked from commit 9131f8cc2b4eaf7c08d402243429e0bfba9aa0d6) Bug: 111431828 Signed-off-by: Kim Low <kim-huei.low@sony.com> Change-Id: I91f52ca8c6b0c3a7bcd71f3b8bf14df160bd2bb4 Signed-off-by: Siarhei Vishniakou <svv@google.com>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-sony.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 94c00af0270b..3a8efd688ab7 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -975,6 +975,32 @@ static const unsigned int buzz_keymap[] = {
[20] = BTN_TRIGGER_HAPPY20,
};
+static const unsigned int ds4_absmap[] = {
+ [0x30] = ABS_X,
+ [0x31] = ABS_Y,
+ [0x32] = ABS_RX, /* right stick X */
+ [0x33] = ABS_Z, /* L2 */
+ [0x34] = ABS_RZ, /* R2 */
+ [0x35] = ABS_RY, /* right stick Y */
+};
+
+static const unsigned int ds4_keymap[] = {
+ [0x1] = BTN_WEST, /* Square */
+ [0x2] = BTN_SOUTH, /* Cross */
+ [0x3] = BTN_EAST, /* Circle */
+ [0x4] = BTN_NORTH, /* Triangle */
+ [0x5] = BTN_TL, /* L1 */
+ [0x6] = BTN_TR, /* R1 */
+ [0x7] = BTN_TL2, /* L2 */
+ [0x8] = BTN_TR2, /* R2 */
+ [0x9] = BTN_SELECT, /* Share */
+ [0xa] = BTN_START, /* Options */
+ [0xb] = BTN_THUMBL, /* L3 */
+ [0xc] = BTN_THUMBR, /* R3 */
+ [0xd] = BTN_MODE, /* PS */
+};
+
+
static enum power_supply_property sony_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CAPACITY,
@@ -1141,6 +1167,37 @@ static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi,
return 1;
}
+static int ds4_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
+ unsigned int key = usage->hid & HID_USAGE;
+
+ if (key >= ARRAY_SIZE(ds4_keymap))
+ return -1;
+
+ key = ds4_keymap[key];
+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key);
+ return 1;
+ } else if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK) {
+ unsigned int abs = usage->hid & HID_USAGE;
+
+ /* Let the HID parser deal with the HAT. */
+ if (usage->hid == HID_GD_HATSWITCH)
+ return 0;
+
+ if (abs >= ARRAY_SIZE(ds4_absmap))
+ return -1;
+
+ abs = ds4_absmap[abs];
+ hid_map_usage_clear(hi, usage, bit, max, EV_ABS, abs);
+ return 1;
+ }
+
+ return 0;
+}
+
static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc,
unsigned int *rsize)
{
@@ -1411,6 +1468,10 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
if (sc->quirks & PS3REMOTE)
return ps3remote_mapping(hdev, hi, field, usage, bit, max);
+
+ if (sc->quirks & DUALSHOCK4_CONTROLLER)
+ return ds4_mapping(hdev, hi, field, usage, bit, max);
+
/* Let hid-core decide for the others */
return 0;
}
@@ -2576,6 +2637,15 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
else if (sc->quirks & SIXAXIS_CONTROLLER)
connect_mask |= HID_CONNECT_HIDDEV_FORCE;
+ /* Patch the hw version on DS4 compatible devices, so applications can
+ * distinguish between the default HID mappings and the mappings defined
+ * by the Linux game controller spec. This is important for the SDL2
+ * library, which has a game controller database, which uses device ids
+ * in combination with version as a key.
+ */
+ if (sc->quirks & DUALSHOCK4_CONTROLLER)
+ hdev->version |= 0x8000;
+
ret = hid_hw_start(hdev, connect_mask);
if (ret) {
hid_err(hdev, "hw start failed\n");