From patchwork Tue Mar 7 23:45:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roderick Colenbrander X-Patchwork-Id: 9610001 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 2A74A6046A for ; Tue, 7 Mar 2017 23:47:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1AE1727D0E for ; Tue, 7 Mar 2017 23:47:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0F7DC28445; Tue, 7 Mar 2017 23:47:00 +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 6B77727DA4 for ; Tue, 7 Mar 2017 23:46:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933257AbdCGXq6 (ORCPT ); Tue, 7 Mar 2017 18:46:58 -0500 Received: from mail-pf0-f173.google.com ([209.85.192.173]:33345 "EHLO mail-pf0-f173.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933283AbdCGXqo (ORCPT ); Tue, 7 Mar 2017 18:46:44 -0500 Received: by mail-pf0-f173.google.com with SMTP id w189so6663912pfb.0 for ; Tue, 07 Mar 2017 15:45:26 -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=8+y8pTVYoNHdIfaIGYoBCzgoNrrqTEoyq6LAErZkjH0=; b=J/LcCr4Osl7b7hTnZzULlInk8I+EV+ZkLhYhCdB2ueQrMV0ubcop6UF/3jHHnKb49c 5R9EYk8HZtmy8EqP0J0+OfXYo2EAmdav+wLbFU/OSFE4z6HXeYHIlPaK5T94QcBHBRfS /788lqaJpDtffqn+XhaxZ+C6bfS4tlHIgD6N/2bxRnQE757X4qKZuwKsWeLhc0NuqXTq ampHa74f7yCiUqtrGx0tNw9GG1TLdN9SeHTNsOQIq6P175uAKC9KVx3uqh8x7HN3Qx5C jcwsELZAmSwtD+r6g5YPIoYktu5YpO805JqxD3Fjr62eSaiRi6cW0zqc7mHR8vVfEXTw 3YQw== 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=8+y8pTVYoNHdIfaIGYoBCzgoNrrqTEoyq6LAErZkjH0=; b=NhuROfvqkAXs6h0GNZm4+Oa4crlGPTsEtDhN7Hmd1YotrzByOPAS165zR3WgygT7rN LG2dRClCKCFNcvnf9eu8qtIeK4HFPKv7u7f1CXD7gUHvZKhfDdziBYaP3erXewGc+8Il DxUNZiK6/gZ2ch/PRbxd7Ra8dpp1l6FB+bCN4cRmVMiw0bpI/As06kHsBv4zUghFNVEj SCjXHq6i3I0o0djeDmfkkuPevWV1sBwIovUcZFOD0UjstnOgaFiHFtDkMt34z3M8BBy8 mkQvi+KFQv8vA3ry/dHKvbwx1JxVcRPgDYuAkpBpdY081Tf5DQU7p5DkIlE1pQfMGIne 0PIA== X-Gm-Message-State: AMke39lnNX3HAoeARd8dR0oc4wKzCb/GpmI///sCKUak2Q+8eLDnGTWPOv516cY9JctYtReH X-Received: by 10.98.9.29 with SMTP id e29mr3414670pfd.101.1488930325685; Tue, 07 Mar 2017 15:45:25 -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.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Mar 2017 15:45:25 -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 11/12] HID: sony: Expose DS3 motion sensors through separate device Date: Tue, 7 Mar 2017 15:45:10 -0800 Message-Id: <20170307234511.30380-12-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 This patch adds a separate evdev node for the DS3 its motion sensors. We only expose the accelerometers as the gyroscope is extremely difficult to manage and behavior varies a lot between hardware revisions. Signed-off-by: Roderick Colenbrander --- drivers/hid/hid-sony.c | 130 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 105 insertions(+), 25 deletions(-) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index b82d05c..f8c4835 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -547,12 +547,15 @@ struct motion_output_report_02 { #define DS4_INPUT_REPORT_BATTERY_OFFSET 30 #define DS4_INPUT_REPORT_TOUCHPAD_OFFSET 33 -#define DS4_SENSOR_SUFFIX " Motion Sensors" +#define SENSOR_SUFFIX " Motion Sensors" #define DS4_TOUCHPAD_SUFFIX " Touchpad" #define DS4_GYRO_RES_PER_DEG_S 1024 #define DS4_ACC_RES_PER_G 8192 +#define SIXAXIS_INPUT_REPORT_ACC_X_OFFSET 41 +#define SIXAXIS_ACC_RES_PER_G 113 + static DEFINE_SPINLOCK(sony_dev_list_lock); static LIST_HEAD(sony_device_list); static DEFINE_IDA(sony_device_id_allocator); @@ -841,6 +844,23 @@ static void sixaxis_parse_report(struct sony_sc *sc, u8 *rd, int size) sc->battery_capacity = battery_capacity; sc->battery_charging = battery_charging; spin_unlock_irqrestore(&sc->lock, flags); + + if (sc->quirks & SIXAXIS_CONTROLLER) { + int val; + + offset = SIXAXIS_INPUT_REPORT_ACC_X_OFFSET; + val = ((rd[offset+1] << 8) | rd[offset]) - 511; + input_report_abs(sc->sensor_dev, ABS_X, val); + + /* Y and Z are swapped and inversed */ + val = 511 - ((rd[offset+5] << 8) | rd[offset+4]); + input_report_abs(sc->sensor_dev, ABS_Y, val); + + val = 511 - ((rd[offset+3] << 8) | rd[offset+2]); + input_report_abs(sc->sensor_dev, ABS_Z, val); + + input_sync(sc->sensor_dev); + } } static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) @@ -1285,33 +1305,49 @@ static int sony_register_sensors(struct sony_sc *sc) /* Append a suffix to the controller name as there are various * DS4 compatible non-Sony devices with different names. */ - name_sz = strlen(sc->hdev->name) + sizeof(DS4_SENSOR_SUFFIX); + name_sz = strlen(sc->hdev->name) + sizeof(SENSOR_SUFFIX); name = kzalloc(name_sz, GFP_KERNEL); if (!name) { ret = -ENOMEM; goto err; } - snprintf(name, name_sz, "%s" DS4_SENSOR_SUFFIX, sc->hdev->name); + snprintf(name, name_sz, "%s" SENSOR_SUFFIX, sc->hdev->name); sc->sensor_dev->name = name; - range = DS4_ACC_RES_PER_G*4; - input_set_abs_params(sc->sensor_dev, ABS_X, -range, range, 16, 0); - input_set_abs_params(sc->sensor_dev, ABS_Y, -range, range, 16, 0); - input_set_abs_params(sc->sensor_dev, ABS_Z, -range, range, 16, 0); - input_abs_set_res(sc->sensor_dev, ABS_X, DS4_ACC_RES_PER_G); - input_abs_set_res(sc->sensor_dev, ABS_Y, DS4_ACC_RES_PER_G); - input_abs_set_res(sc->sensor_dev, ABS_Z, DS4_ACC_RES_PER_G); - - range = DS4_GYRO_RES_PER_DEG_S*2048; - input_set_abs_params(sc->sensor_dev, ABS_RX, -range, range, 16, 0); - input_set_abs_params(sc->sensor_dev, ABS_RY, -range, range, 16, 0); - input_set_abs_params(sc->sensor_dev, ABS_RZ, -range, range, 16, 0); - input_abs_set_res(sc->sensor_dev, ABS_RX, DS4_GYRO_RES_PER_DEG_S); - input_abs_set_res(sc->sensor_dev, ABS_RY, DS4_GYRO_RES_PER_DEG_S); - input_abs_set_res(sc->sensor_dev, ABS_RZ, DS4_GYRO_RES_PER_DEG_S); - - __set_bit(EV_MSC, sc->sensor_dev->evbit); - __set_bit(MSC_TIMESTAMP, sc->sensor_dev->mscbit); + if (sc->quirks & SIXAXIS_CONTROLLER) { + /* For the DS3 we only support the accelerometer, which works + * quite well even without calibration. The device also has + * a 1-axis gyro, but it is very difficult to manage from within + * the driver even to get data, the sensor is inaccurate and + * the behavior is very different between hardware revisions. + */ + input_set_abs_params(sc->sensor_dev, ABS_X, -512, 511, 4, 0); + input_set_abs_params(sc->sensor_dev, ABS_Y, -512, 511, 4, 0); + input_set_abs_params(sc->sensor_dev, ABS_Z, -512, 511, 4, 0); + input_abs_set_res(sc->sensor_dev, ABS_X, SIXAXIS_ACC_RES_PER_G); + input_abs_set_res(sc->sensor_dev, ABS_Y, SIXAXIS_ACC_RES_PER_G); + input_abs_set_res(sc->sensor_dev, ABS_Z, SIXAXIS_ACC_RES_PER_G); + } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { + range = DS4_ACC_RES_PER_G*4; + input_set_abs_params(sc->sensor_dev, ABS_X, -range, range, 16, 0); + input_set_abs_params(sc->sensor_dev, ABS_Y, -range, range, 16, 0); + input_set_abs_params(sc->sensor_dev, ABS_Z, -range, range, 16, 0); + input_abs_set_res(sc->sensor_dev, ABS_X, DS4_ACC_RES_PER_G); + input_abs_set_res(sc->sensor_dev, ABS_Y, DS4_ACC_RES_PER_G); + input_abs_set_res(sc->sensor_dev, ABS_Z, DS4_ACC_RES_PER_G); + + range = DS4_GYRO_RES_PER_DEG_S*2048; + input_set_abs_params(sc->sensor_dev, ABS_RX, -range, range, 16, 0); + input_set_abs_params(sc->sensor_dev, ABS_RY, -range, range, 16, 0); + input_set_abs_params(sc->sensor_dev, ABS_RZ, -range, range, 16, 0); + input_abs_set_res(sc->sensor_dev, ABS_RX, DS4_GYRO_RES_PER_DEG_S); + input_abs_set_res(sc->sensor_dev, ABS_RY, DS4_GYRO_RES_PER_DEG_S); + input_abs_set_res(sc->sensor_dev, ABS_RZ, DS4_GYRO_RES_PER_DEG_S); + + __set_bit(EV_MSC, sc->sensor_dev->evbit); + __set_bit(MSC_TIMESTAMP, sc->sensor_dev->mscbit); + } + __set_bit(INPUT_PROP_ACCELEROMETER, sc->sensor_dev->propbit); ret = input_register_device(sc->sensor_dev); @@ -2447,8 +2483,7 @@ static int sony_input_configured(struct hid_device *hdev, goto err_stop; } - if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || - (sc->quirks & NAVIGATION_CONTROLLER_USB)) { + if (sc->quirks & NAVIGATION_CONTROLLER_USB) { /* * The Sony Sixaxis does not handle HID Output Reports on the * Interrupt EP like it could, so we need to force HID Output @@ -2476,8 +2511,46 @@ static int sony_input_configured(struct hid_device *hdev, } sony_init_output_report(sc, sixaxis_send_output_report); - } else if ((sc->quirks & SIXAXIS_CONTROLLER_BT) || - (sc->quirks & NAVIGATION_CONTROLLER_BT)) { + } else if (sc->quirks & NAVIGATION_CONTROLLER_BT) { + /* + * The Navigation controller wants output reports sent on the ctrl + * endpoint when connected via Bluetooth. + */ + hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP; + + ret = sixaxis_set_operational_bt(hdev); + if (ret < 0) { + hid_err(hdev, "Failed to set controller into operational mode\n"); + goto err_stop; + } + + sony_init_output_report(sc, sixaxis_send_output_report); + } else if (sc->quirks & SIXAXIS_CONTROLLER_USB) { + /* + * The Sony Sixaxis does not handle HID Output Reports on the + * Interrupt EP and the device only becomes active when the + * PS button is pressed. See comment for Navigation controller + * above for more details. + */ + hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP; + hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID; + sc->defer_initialization = 1; + + ret = sixaxis_set_operational_usb(hdev); + if (ret < 0) { + hid_err(hdev, "Failed to set controller into operational mode\n"); + goto err_stop; + } + + ret = sony_register_sensors(sc); + if (ret) { + hid_err(sc->hdev, + "Unable to initialize motion sensors: %d\n", ret); + goto err_stop; + } + + sony_init_output_report(sc, sixaxis_send_output_report); + } else if (sc->quirks & SIXAXIS_CONTROLLER_BT) { /* * The Sixaxis wants output reports sent on the ctrl endpoint * when connected via Bluetooth. @@ -2490,6 +2563,13 @@ static int sony_input_configured(struct hid_device *hdev, goto err_stop; } + ret = sony_register_sensors(sc); + if (ret) { + hid_err(sc->hdev, + "Unable to initialize motion sensors: %d\n", ret); + goto err_stop; + } + sony_init_output_report(sc, sixaxis_send_output_report); } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { ret = dualshock4_get_calibration_data(sc);