From patchwork Tue Mar 7 23:45:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roderick Colenbrander X-Patchwork-Id: 9609997 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 588D76046A for ; Tue, 7 Mar 2017 23:46:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 46C9227DA4 for ; Tue, 7 Mar 2017 23:46:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 38ED728445; Tue, 7 Mar 2017 23:46:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.3 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7292425F31 for ; Tue, 7 Mar 2017 23:46:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933268AbdCGXq4 (ORCPT ); Tue, 7 Mar 2017 18:46:56 -0500 Received: from mail-pg0-f48.google.com ([74.125.83.48]:35941 "EHLO mail-pg0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933278AbdCGXqo (ORCPT ); Tue, 7 Mar 2017 18:46:44 -0500 Received: by mail-pg0-f48.google.com with SMTP id 187so5985386pgb.3 for ; Tue, 07 Mar 2017 15:45:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gaikai-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=gOctIxo/SO3IMSrJnPK8/SmhB7+nZHxmBcMWRIq7JxI=; b=yDtIdswpPRq91lvi6WgiRXyCZ5+RURFlvnh2bnezB1B9jL8jHTJMYII2lGhxYUKnKg pgGunHO7tBgLjz6NxR1QQUj5iqwg3RlC2cKRJI4PsRp2BgjjrMKET5vr7dgRHsen1EwH v+pg6+HnSphHYX4a3/pBvP1WIse7NZrXBIvbRoTems02On3Pao0L1lNGuLkVVIES1V6n DtY2PV7D6Y52vidXa6MgdEtY5Vytpzws998QXTiWLesSaRM8J++L0LMnjpBxXTH8rED3 pKYoCKnSeuHfRNapDHZvEtlfSRYKGLNIu9XHPuwDT4vgm85oCpnXyC0CRgCMKfWu6uiB B2Tw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=gOctIxo/SO3IMSrJnPK8/SmhB7+nZHxmBcMWRIq7JxI=; b=XYTOc1/4zAS6KfqH/RHo5BgH0jYjzQ5A6zQbUFZzgxc6wel36EcSb0eXWJ3LmDncXr qruWp/AwkYexlsckfwJND77AzUVlFi7griUAI9C7O4S/Huy5YV7Q635tMpuk5lvn0dMt FPH9AxEc0x1frKDISOSyX/cqLI5WGYBxTaOu6RxJSMBTJ1g1bUvp3ZcPPdQRr+/oxRkA EhAt4LqEGnxmKrQKUvltwVLNaDnpdQQdSdhhf9+l8NKHTYRCj3z1IVRSSUlGwOzDXiS3 PleoIP+Zjykiyi7yCE+8vkYvzO2MaGKhioI5wqQkvN+N4JQKmQ9OgNRF0Z8Yd5FPh8gI HBlg== X-Gm-Message-State: AMke39kATE2Cv/Jm98NRFUP0TpAX1uY8ZTA56fFjRquvtS16Dop44yoOrt4+zPjNalSFCXqq X-Received: by 10.98.1.10 with SMTP id 10mr3324103pfb.117.1488930323642; Tue, 07 Mar 2017 15:45:23 -0800 (PST) Received: from roderick.ad.gaikai.biz ([100.42.98.197]) by smtp.gmail.com with ESMTPSA id e7sm1890993pgp.2.2017.03.07.15.45.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Mar 2017 15:45:23 -0800 (PST) From: Roderick Colenbrander To: linux-input@vger.kernel.org Cc: Dmitry Torokhov , Jiri Kosina , Benjamin Tissoires , Simon Wood , Frank Praznik , Tim Bird , Roderick Colenbrander Subject: [PATCH 09/12] HID: sony: DS3 comply to Linux gamepad spec Date: Tue, 7 Mar 2017 15:45:08 -0800 Message-Id: <20170307234511.30380-10-roderick@gaikai.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170307234511.30380-1-roderick@gaikai.com> References: <20170307234511.30380-1-roderick@gaikai.com> Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Roderick Colenbrander The axis and button mapping for the DS3 is strange. This is mostly due to the device reporting many axes as for every digital button it also has an analog button. Due to amount of analog values it is even leaking well into the MT axes range. We felt it is best to remove the many analog buttons and just report digital and comply to the Linux gamepad spec. The analog buttons are rarely used on the official platform, let alone on Linux. This patch does remove motion sensor support (added back in another patch). Signed-off-by: Roderick Colenbrander --- drivers/hid/hid-sony.c | 176 +++++++++++++++++++++++-------------------------- 1 file changed, 81 insertions(+), 95 deletions(-) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 1c62698..16f37d6 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -75,89 +75,6 @@ #define MAX_LEDS 4 -/* - * The Sixaxis reports both digital and analog values for each button on the - * controller except for Start, Select and the PS button. The controller ends - * up reporting 27 axes which causes them to spill over into the multi-touch - * axis values. Additionally, the controller only has 20 actual, physical axes - * so there are several unused axes in between the used ones. - */ -static u8 sixaxis_rdesc[] = { - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x04, /* Usage (Joystick), */ - 0xA1, 0x01, /* Collection (Application), */ - 0xA1, 0x02, /* Collection (Logical), */ - 0x85, 0x01, /* Report ID (1), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x01, /* Report Count (1), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x75, 0x01, /* Report Size (1), */ - 0x95, 0x13, /* Report Count (19), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x25, 0x01, /* Logical Maximum (1), */ - 0x35, 0x00, /* Physical Minimum (0), */ - 0x45, 0x01, /* Physical Maximum (1), */ - 0x05, 0x09, /* Usage Page (Button), */ - 0x19, 0x01, /* Usage Minimum (01h), */ - 0x29, 0x13, /* Usage Maximum (13h), */ - 0x81, 0x02, /* Input (Variable), */ - 0x75, 0x01, /* Report Size (1), */ - 0x95, 0x0D, /* Report Count (13), */ - 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x81, 0x03, /* Input (Constant, Variable), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xA1, 0x00, /* Collection (Physical), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x04, /* Report Count (4), */ - 0x35, 0x00, /* Physical Minimum (0), */ - 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ - 0x09, 0x30, /* Usage (X), */ - 0x09, 0x31, /* Usage (Y), */ - 0x09, 0x32, /* Usage (Z), */ - 0x09, 0x35, /* Usage (Rz), */ - 0x81, 0x02, /* Input (Variable), */ - 0xC0, /* End Collection, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x95, 0x13, /* Report Count (19), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x0C, /* Report Count (12), */ - 0x81, 0x01, /* Input (Constant), */ - 0x75, 0x10, /* Report Size (16), */ - 0x95, 0x04, /* Report Count (4), */ - 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ - 0x46, 0xFF, 0x03, /* Physical Maximum (1023), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0x81, 0x02, /* Input (Variable), */ - 0xC0, /* End Collection, */ - 0xA1, 0x02, /* Collection (Logical), */ - 0x85, 0x02, /* Report ID (2), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x30, /* Report Count (48), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0xC0, /* End Collection, */ - 0xA1, 0x02, /* Collection (Logical), */ - 0x85, 0xEE, /* Report ID (238), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x30, /* Report Count (48), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0xC0, /* End Collection, */ - 0xA1, 0x02, /* Collection (Logical), */ - 0x85, 0xEF, /* Report ID (239), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x30, /* Report Count (48), */ - 0x09, 0x01, /* Usage (Pointer), */ - 0xB1, 0x02, /* Feature (Variable), */ - 0xC0, /* End Collection, */ - 0xC0 /* End Collection */ -}; /* PS/3 Motion controller */ static u8 motion_rdesc[] = { @@ -508,6 +425,34 @@ static const unsigned int buzz_keymap[] = { [20] = BTN_TRIGGER_HAPPY20, }; +static const unsigned int sixaxis_absmap[] = { + [0x30] = ABS_X, + [0x31] = ABS_Y, + [0x32] = ABS_RX, /* right stick X */ + [0x35] = ABS_RY, /* right stick Y */ +}; + +static const unsigned int sixaxis_keymap[] = { + [0x01] = BTN_SELECT, /* Select */ + [0x02] = BTN_THUMBL, /* L3 */ + [0x03] = BTN_THUMBR, /* R3 */ + [0x04] = BTN_START, /* Start */ + [0x05] = BTN_DPAD_UP, /* Up */ + [0x06] = BTN_DPAD_RIGHT, /* Right */ + [0x07] = BTN_DPAD_DOWN, /* Down */ + [0x08] = BTN_DPAD_LEFT, /* Left */ + [0x09] = BTN_TL2, /* L2 */ + [0x0a] = BTN_TR2, /* R2 */ + [0x0b] = BTN_TL, /* L1 */ + [0x0c] = BTN_TR, /* R1 */ + [0x0d] = BTN_NORTH, /* Triangle */ + [0x0e] = BTN_EAST, /* Circle */ + [0x0f] = BTN_SOUTH, /* Cross */ + [0x10] = BTN_WEST, /* Square */ + [0x11] = BTN_MODE, /* PS */ +}; + + static const unsigned int ds4_absmap[] = { [0x30] = ABS_X, [0x31] = ABS_Y, @@ -695,13 +640,6 @@ static inline void sony_schedule_work(struct sony_sc *sc, } } -static u8 *sixaxis_fixup(struct hid_device *hdev, u8 *rdesc, - unsigned int *rsize) -{ - *rsize = sizeof(sixaxis_rdesc); - return sixaxis_rdesc; -} - static u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *rsize) { @@ -757,6 +695,54 @@ static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } +static int sixaxis_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(sixaxis_keymap)) + return -1; + + key = sixaxis_keymap[key]; + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key); + return 1; + } else if (usage->hid == HID_GD_POINTER) { + /* The DS3 provides analog values for most buttons and even + * for HAT axes through GD Pointer. L2 and R2 are reported + * among these as well instead of as GD Z / RZ. Remap L2 + * and R2 and ignore other analog 'button axes' as there is + * no good way for reporting them. + */ + switch (usage->usage_index) { + case 8: /* L2 */ + usage->hid = HID_GD_Z; + break; + case 9: /* R2 */ + usage->hid = HID_GD_RZ; + break; + default: + return -1; + } + + hid_map_usage_clear(hi, usage, bit, max, EV_ABS, usage->hid & 0xf); + return 1; + } else if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK) { + unsigned int abs = usage->hid & HID_USAGE; + + if (abs >= ARRAY_SIZE(sixaxis_absmap)) + return -1; + + abs = sixaxis_absmap[abs]; + + hid_map_usage_clear(hi, usage, bit, max, EV_ABS, abs); + return 1; + } + + 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) @@ -812,9 +798,6 @@ static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc, rdesc[55] = 0x06; } - if (sc->quirks & SIXAXIS_CONTROLLER) - return sixaxis_fixup(hdev, rdesc, rsize); - if (sc->quirks & MOTION_CONTROLLER) return motion_fixup(hdev, rdesc, rsize); @@ -1196,10 +1179,13 @@ 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 & SIXAXIS_CONTROLLER) + return sixaxis_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; } @@ -2618,13 +2604,13 @@ 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 + /* Patch the hw version on DS3/4 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) + if (sc->quirks & (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER)) hdev->version |= 0x8000; ret = hid_hw_start(hdev, connect_mask);