From patchwork Wed Nov 23 22:07:07 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roderick Colenbrander X-Patchwork-Id: 9444411 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 79EEB60235 for ; Wed, 23 Nov 2016 22:08:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7382D271CB for ; Wed, 23 Nov 2016 22:08:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 683A627D8D; Wed, 23 Nov 2016 22:08:15 +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 C1BD0271CB for ; Wed, 23 Nov 2016 22:08:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933810AbcKWWIM (ORCPT ); Wed, 23 Nov 2016 17:08:12 -0500 Received: from mail-yw0-f169.google.com ([209.85.161.169]:35797 "EHLO mail-yw0-f169.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933813AbcKWWIL (ORCPT ); Wed, 23 Nov 2016 17:08:11 -0500 Received: by mail-yw0-f169.google.com with SMTP id i145so23766209ywg.2 for ; Wed, 23 Nov 2016 14:08:10 -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=jIv40EsKm3iD0fH7e33qRPNMTS4lfpmsvsXdfDr+tK8=; b=fiqQuRJDRir08yK5awGlaZS+hGHRofzx5xMzmDFZnIocROrfremgAxYwelt2w0yVuE VC36vaUhjklmZhEvEiauJ79ZNNwtTmcnWIXrtgLebXBDjVodONeE5qdEgrUQ8qsu8jMm k0wEUP1kH7qhDy1ELbucDA6Cdah6fLSs+lCAPyxmiCgXcB5YDOM40zVK7/7SBvfmS50l Z4IT8QfL2lnwBnCmtEIWn2V8m4XdWATQXLceGwQRIB4BJvNeQhDz79E3ER+RfriNe81O WgBenuC8tu6hKRFZTX0hvlX28fsDjTuZZ2wGnb5Jpuoo7cdMhkZONZpE56JhkemBCWXo ng6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=jIv40EsKm3iD0fH7e33qRPNMTS4lfpmsvsXdfDr+tK8=; b=YuRS4VFoiABtD2t/rpSA9Em2au2A25PM9EapvvNxcCfhaP6HJpXa/Y+xioIwc2liBy pKAR2fzOhJqW63ZLZq00AZ9Uj5PMriDg0oNhDezmWqmdJQa32DJ9x83JsCBQmIFaSbpx vljJ4KCdPAz3Xck99mBtRfEuX9Xz9PU9IVjG6oKjjGgPnvpMjm73Tktf3cOXsPO2wzcz P3VTUN1bOGRaKRKxYA7ixIT/N+rVpocgwqTsuhaD+3Y9pkmsQmgs4OZri0zfWyI0klGw 3wImcmVHjU0noOJsBZdlzkiH8aSByZD0fhPw7cJ7cyQ83CER/XPB7OHwLRHyWuHjkt8j W4/g== X-Gm-Message-State: AKaTC02KjdDV3tc/E3LcFRJEsersiqNP0CRVkJ3gFzeo9GNDTXBBQbptohiL4rU0ntuZyjt7 X-Received: by 10.13.213.206 with SMTP id x197mr7036340ywd.299.1479938890152; Wed, 23 Nov 2016 14:08:10 -0800 (PST) Received: from konan1.dev.biz ([100.42.98.197]) by smtp.gmail.com with ESMTPSA id u134sm12154004ywg.31.2016.11.23.14.08.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 23 Nov 2016 14:08:09 -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 2/8] HID: sony: Make the DS4 touchpad a separate device Date: Wed, 23 Nov 2016 14:07:07 -0800 Message-Id: <1479938833-26424-3-git-send-email-roderick@gaikai.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1479938833-26424-1-git-send-email-roderick@gaikai.com> References: <1479938833-26424-1-git-send-email-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 dualshock 4 supports both analog sticks of which one uses ABS_X/_Y and a touchpad. In a recent discussion with Dmitry about some input-mt changes we proposed for disabling pointer emulation from input_mt_sync_frame, Dmitry mentioned ABS_X/_Y should report the same data as ABS_MT_POSITION_X/_Y. The current driver is mixing axes for different subdevices. It was suggested to make the touchpad its own sub-device. This patch turns the touchpad into its own device. In addition this patch also moves the button underneath the touchpad into the new device. It felt like this button should be part of the device. No known user space application (not even SDL2) seems to be using it. Signed-off-by: Roderick Colenbrander --- drivers/hid/hid-sony.c | 105 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 84 insertions(+), 21 deletions(-) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 3385006..995b5cf 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -376,7 +376,7 @@ static u8 dualshock4_usb_rdesc[] = { 0x65, 0x00, /* Unit, */ 0x05, 0x09, /* Usage Page (Button), */ 0x19, 0x01, /* Usage Minimum (01h), */ - 0x29, 0x0E, /* Usage Maximum (0Eh), */ + 0x29, 0x0D, /* Usage Maximum (0Dh), */ 0x15, 0x00, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ @@ -689,7 +689,7 @@ static u8 dualshock4_bt_rdesc[] = { 0x81, 0x42, /* Input (Variable, Null State), */ 0x05, 0x09, /* Usage Page (Button), */ 0x19, 0x01, /* Usage Minimum (01h), */ - 0x29, 0x0E, /* Usage Maximum (0Eh), */ + 0x29, 0x0D, /* Usage Maximum (0Dh), */ 0x15, 0x00, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x75, 0x01, /* Report Size (1), */ @@ -1033,9 +1033,12 @@ struct motion_output_report_02 { /* Offsets relative to USB input report (0x1). Bluetooth (0x11) requires an * additional +2. */ +#define DS4_INPUT_REPORT_BUTTON_OFFSET 5 #define DS4_INPUT_REPORT_BATTERY_OFFSET 30 #define DS4_INPUT_REPORT_TOUCHPAD_OFFSET 33 +#define DS4_TOUCHPAD_SUFFIX " Touchpad" + static DEFINE_SPINLOCK(sony_dev_list_lock); static LIST_HEAD(sony_device_list); static DEFINE_IDA(sony_device_id_allocator); @@ -1044,6 +1047,7 @@ struct sony_sc { spinlock_t lock; struct list_head list_node; struct hid_device *hdev; + struct input_dev *touchpad; struct led_classdev *leds[MAX_LEDS]; unsigned long quirks; struct work_struct state_worker; @@ -1228,9 +1232,6 @@ static void sixaxis_parse_report(struct sony_sc *sc, u8 *rd, int size) static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) { - struct hid_input *hidinput = list_entry(sc->hdev->inputs.next, - struct hid_input, list); - struct input_dev *input_dev = hidinput->input; unsigned long flags; int n, m, offset, num_touch_data, max_touch_data; u8 cable_state, battery_capacity, battery_charging; @@ -1238,6 +1239,10 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) /* When using Bluetooth the header is 2 bytes longer, so skip these. */ int data_offset = (sc->quirks & DUALSHOCK4_CONTROLLER_USB) ? 0 : 2; + /* Second bit of third button byte is for the touchpad button. */ + offset = data_offset + DS4_INPUT_REPORT_BUTTON_OFFSET; + input_report_key(sc->touchpad, BTN_LEFT, rd[offset+2] & 0x2); + /* * The lower 4 bits of byte 30 (or 32 for BT) contain the battery level * and the 5th bit contains the USB cable state. @@ -1303,18 +1308,18 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) y = ((rd[offset+2] & 0xF0) >> 4) | (rd[offset+3] << 4); active = !(rd[offset] >> 7); - input_mt_slot(input_dev, n); - input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, active); + input_mt_slot(sc->touchpad, n); + input_mt_report_slot_state(sc->touchpad, MT_TOOL_FINGER, active); if (active) { - input_report_abs(input_dev, ABS_MT_POSITION_X, x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, y); + input_report_abs(sc->touchpad, ABS_MT_POSITION_X, x); + input_report_abs(sc->touchpad, ABS_MT_POSITION_Y, y); } offset += 4; } - input_mt_sync_frame(input_dev); - input_sync(input_dev); + input_mt_sync_frame(sc->touchpad); + input_sync(sc->touchpad); } } @@ -1415,22 +1420,77 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi, return 0; } -static int sony_register_touchpad(struct hid_input *hi, int touch_count, +static int sony_register_touchpad(struct sony_sc *sc, int touch_count, int w, int h) { - struct input_dev *input_dev = hi->input; + size_t name_sz; + char *name; int ret; - ret = input_mt_init_slots(input_dev, touch_count, 0); + sc->touchpad = input_allocate_device(); + if (!sc->touchpad) + return -ENOMEM; + + input_set_drvdata(sc->touchpad, sc); + sc->touchpad->dev.parent = &sc->hdev->dev; + sc->touchpad->phys = sc->hdev->phys; + sc->touchpad->uniq = sc->hdev->uniq; + sc->touchpad->id.bustype = sc->hdev->bus; + sc->touchpad->id.vendor = sc->hdev->vendor; + sc->touchpad->id.product = sc->hdev->product; + sc->touchpad->id.version = sc->hdev->version; + + /* 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_TOUCHPAD_SUFFIX); + name = kzalloc(name_sz, GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto err; + } + snprintf(name, name_sz, "%s" DS4_TOUCHPAD_SUFFIX, sc->hdev->name); + sc->touchpad->name = name; + + ret = input_mt_init_slots(sc->touchpad, touch_count, 0); if (ret < 0) - return ret; + goto err; + + /* We map the button underneath the touchpad to BTN_LEFT. */ + __set_bit(EV_KEY, sc->touchpad->evbit); + __set_bit(BTN_LEFT, sc->touchpad->keybit); + __set_bit(INPUT_PROP_BUTTONPAD, sc->touchpad->propbit); - input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, w, 0, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, h, 0, 0); + input_set_abs_params(sc->touchpad, ABS_MT_POSITION_X, 0, w, 0, 0); + input_set_abs_params(sc->touchpad, ABS_MT_POSITION_Y, 0, h, 0, 0); + + ret = input_register_device(sc->touchpad); + if (ret < 0) + goto err; return 0; + +err: + kfree(sc->touchpad->name); + sc->touchpad->name = NULL; + + input_free_device(sc->touchpad); + sc->touchpad = NULL; + + return ret; } +static void sony_unregister_touchpad(struct sony_sc *sc) +{ + if (!sc->touchpad) + return; + + kfree(sc->touchpad->name); + sc->touchpad->name = NULL; + + input_unregister_device(sc->touchpad); + sc->touchpad = NULL; +} /* * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller @@ -2422,7 +2482,7 @@ static int sony_input_configured(struct hid_device *hdev, * The Dualshock 4 touchpad supports 2 touches and has a * resolution of 1920x942 (44.86 dots/mm). */ - ret = sony_register_touchpad(hidinput, 2, 1920, 942); + ret = sony_register_touchpad(sc, 2, 1920, 942); if (ret) { hid_err(sc->hdev, "Unable to initialize multi-touch slots: %d\n", @@ -2544,13 +2604,16 @@ static void sony_remove(struct hid_device *hdev) { struct sony_sc *sc = hid_get_drvdata(hdev); + hid_hw_close(hdev); + if (sc->quirks & SONY_LED_SUPPORT) sony_leds_remove(sc); - if (sc->quirks & SONY_BATTERY_SUPPORT) { - hid_hw_close(hdev); + if (sc->quirks & SONY_BATTERY_SUPPORT) sony_battery_remove(sc); - } + + if (sc->touchpad) + sony_unregister_touchpad(sc); sony_cancel_work_sync(sc);