From patchwork Sat Feb 17 23:47:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Todd Kelner X-Patchwork-Id: 10226651 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 9BF97601D4 for ; Sat, 17 Feb 2018 23:47:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 99D1128A6E for ; Sat, 17 Feb 2018 23:47:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8E51928A72; Sat, 17 Feb 2018 23:47:18 +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.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, 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 B08D428A9B for ; Sat, 17 Feb 2018 23:47:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751083AbeBQXrN (ORCPT ); Sat, 17 Feb 2018 18:47:13 -0500 Received: from mail-pg0-f65.google.com ([74.125.83.65]:33180 "EHLO mail-pg0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751101AbeBQXrM (ORCPT ); Sat, 17 Feb 2018 18:47:12 -0500 Received: by mail-pg0-f65.google.com with SMTP id g12so4524566pgs.0 for ; Sat, 17 Feb 2018 15:47:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:subject:message-id:mime-version:content-disposition :user-agent; bh=zmCi+3/XyikTOuNEhk7dNWao7W9KZiWSEtuzNdCepeo=; b=UJ+zYGsNES+ozIyzB0ryzWWCSRKXhV1ddnvByJOUMN8dljti1NtLvpZ7kR+o3cH9ra VTbJymi+0ledD05xDKndl+lUH8gIas4RGY1yaYiL5xAgkSJhiw2H2LSWCI6P4/FYBOQU Gzb5ShAcSVOk5reuvK72Gqr8gMk9k3lIGJ0NVmDW9cuEP/f6GLJ+q3ZRA+rkhkzipiwN 7umEy18JWa++xNQnkQQAbqJ0M0wuxO9g3GZ2L8UIlIh5/AaDzwDzvt6nu5xE92oEOuIB H4pGNNt1pTrzm9zGI+Z0he7FaxAP+e2C41rYDxWlpf6UJ0ss/N1Hup1T/omCFCHfESeC GdFg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:subject:message-id:mime-version :content-disposition:user-agent; bh=zmCi+3/XyikTOuNEhk7dNWao7W9KZiWSEtuzNdCepeo=; b=dVCKPiKH0AWUdfzZ0rDsuUze+/xjNY0CR+3NpocS1cWYIeX36eQgo0AX8cIdTODGV/ 4A+anpl7P58nf8h0pDI+REJkqm2BqnQD49AsF0T8KCOIn3X3VSmCynOgu31QWjoOHaHi wms6fG9B8RgXJBYmHHSwPDlkTjvqPau7WO3BtFampSbwdzj/eaDXfIzpDN1ky96FdqsP +mRZkWHVY9S1LodVaXcvGvK+GJajyNpFGQApPT4VNsjqiqW7v7OkZW3KcpBCWBLannN2 T/DO9JAJfLCCkLE4cPxuUL0Ovr0mRD5uevNG9B2h+OM2K3pjKA0zhdS3rEs320c6msaK bnjg== X-Gm-Message-State: APf1xPArdgMpvG2gZhnKg4aNbOKfpDCoaCYr/627XtGDRpT4UU2PELj8 JSFKfTFOjtqpO0c8Txus3Iu8HxgBYKY= X-Google-Smtp-Source: AH8x2266QVmueA/ijFPgl4I8yrnRq2KU8dEjuD5ZeV0rISU8abORDpKdezgjvEyM8qLQVGLT9nfdAg== X-Received: by 10.101.82.198 with SMTP id z6mr341541pgp.41.1518911231769; Sat, 17 Feb 2018 15:47:11 -0800 (PST) Received: from me-C51-MCP51 (S0106a84e3f6ddbc3.ek.shawcable.net. [24.66.190.27]) by smtp.gmail.com with ESMTPSA id t1sm44414026pgu.77.2018.02.17.15.47.11 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 17 Feb 2018 15:47:11 -0800 (PST) Date: Sat, 17 Feb 2018 16:47:10 -0700 From: Todd Kelner To: Jiri Kosina , Benjamin Tissoires , Roderick Colenbrander , linux-input Subject: [PATCH v2] HID: sony: Add touchpad support for NSG-MR5U and NSG-MR7U remotes Message-ID: <20180217234707.GA2922@me-C51-MCP51> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.24 (2015-08-30) 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 Sony's NSG-MR5U and NSG-MR7U remote controls have a full keyboard and a touchpad. The keyboard is already supported by the existing Linux kernel and drivers but the touchpad is not recognized. This patch adds the coded needed to bring full functionality to the touchpad. Note that these remotes use the vendor code for SMK even though they are Sony branded. Known limitations - The built-in accelerometers are not supported by these changes - When the Drag (Fn) key is used as a mouse button, the button is automatically released when the key begins repeating. There are two workarounds for this 1) Use the button behind the touchpad instead of the Drag (Fn) key or 2) Disable the key repeat functionality or increase the key repeat delay. Signed-off-by: Todd Kelner --- Changes in v2: - Brought code up-to-date with latest changes from git - Converted relative trackpad coordinates from unsigned to signed - In sony_register_touchpad, merged two occurrences of input_mt_init_slots into one - Added new parameters to sony_register_trackpad to support touch major and minor and orientation settings drivers/hid/hid-ids.h | 3 ++ drivers/hid/hid-quirks.c | 2 + drivers/hid/hid-sony.c | 131 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 130 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 43ddcdf..5d56387 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -958,6 +958,9 @@ #define USB_VENDOR_ID_SMK 0x0609 #define USB_DEVICE_ID_SMK_PS3_BDREMOTE 0x0306 +#define USB_DEVICE_ID_SMK_NSG_MR5U_REMOTE 0x0368 +#define USB_DEVICE_ID_SMK_NSG_MR7U_REMOTE 0x0369 + #define USB_VENDOR_ID_SONY 0x054c #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 5f6035a..376cbbc 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -608,6 +608,8 @@ static const struct hid_device_id hid_have_special_driver[] = { #if IS_ENABLED(CONFIG_HID_SONY) { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_PS3_BDREMOTE) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR5U_REMOTE) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR7U_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER) }, diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index ccdc5f2..e475c50 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -9,6 +9,7 @@ * Copyright (c) 2006-2013 Jiri Kosina * Copyright (c) 2013 Colin Leitner * Copyright (c) 2014-2016 Frank Praznik + * Copyright (c) 2018 Todd Kelner */ /* @@ -55,6 +56,8 @@ #define NAVIGATION_CONTROLLER_BT BIT(11) #define SINO_LITE_CONTROLLER BIT(12) #define FUTUREMAX_DANCE_MAT BIT(13) +#define NSG_MR5U_REMOTE_BT BIT(14) +#define NSG_MR7U_REMOTE_BT BIT(15) #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) #define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) @@ -72,8 +75,11 @@ MOTION_CONTROLLER) #define SONY_BT_DEVICE (SIXAXIS_CONTROLLER_BT | DUALSHOCK4_CONTROLLER_BT |\ MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER_BT) +#define NSG_MRXU_REMOTE (NSG_MR5U_REMOTE_BT | NSG_MR7U_REMOTE_BT) #define MAX_LEDS 4 +#define NSG_MRXU_MAX_X 1667 +#define NSG_MRXU_MAX_Y 1868 /* PS/3 Motion controller */ @@ -1098,6 +1104,80 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) } } +static void nsg_mrxu_parse_report(struct sony_sc *sc, u8 *rd, int size) +{ + int n, offset, relx, rely; + u8 active; + + /* + * The NSG-MRxU multi-touch trackpad data starts at offset 1 and + * the touch-related data starts at offset 2. + * For the first byte, bit 0 is set when touchpad button is pressed. + * Bit 2 is set when a touch is active and the drag (Fn) key is pressed. + * This drag key is mapped to BTN_LEFT. It is operational only when a + * touch point is active. + * Bit 4 is set when only the first touch point is active. + * Bit 6 is set when only the second touch point is active. + * Bits 5 and 7 are set when both touch points are active. + * The next 3 bytes are two 12 bit X/Y coordinates for the first touch. + * The following byte, offset 5, has the touch width and length. + * Bits 0-4=X (width), bits 5-7=Y (length). + * A signed relative X coordinate is at offset 6. + * The bytes at offset 7-9 are the second touch X/Y coordinates. + * Offset 10 has the second touch width and length. + * Offset 11 has the relative Y coordinate. + */ + offset = 1; + + input_report_key(sc->touchpad, BTN_LEFT, rd[offset] & 0x0F); + active = (rd[offset] >> 4); + relx = (s8) rd[offset+5]; + rely = ((s8) rd[offset+10]) * -1; + + offset++; + + for (n = 0; n < 2; n++) { + u16 x, y; + u8 contactx, contacty; + + x = rd[offset] | ((rd[offset+1] & 0x0F) << 8); + y = ((rd[offset+1] & 0xF0) >> 4) | (rd[offset+2] << 4); + + input_mt_slot(sc->touchpad, n); + input_mt_report_slot_state(sc->touchpad, MT_TOOL_FINGER, active & 0x03); + + if (active & 0x03) { + contactx = rd[offset+3] & 0x0F; + contacty = rd[offset+3] >> 4; + input_report_abs(sc->touchpad, ABS_MT_TOUCH_MAJOR, + max(contactx, contacty)); + input_report_abs(sc->touchpad, ABS_MT_TOUCH_MINOR, + min(contactx, contacty)); + input_report_abs(sc->touchpad, ABS_MT_ORIENTATION, + (bool) (contactx > contacty)); + input_report_abs(sc->touchpad, ABS_MT_POSITION_X, x); + input_report_abs(sc->touchpad, ABS_MT_POSITION_Y, + NSG_MRXU_MAX_Y - y); + /* + * The relative coordinates belong to the first touch + * point, when present, or to the second touch point + * when the first is not active. + */ + if ((n == 0) || ((n == 1) && (active & 0x01))) { + input_report_rel(sc->touchpad, REL_X, relx); + input_report_rel(sc->touchpad, REL_Y, rely); + } + } + + offset += 5; + active >>= 2; + } + + input_mt_sync_frame(sc->touchpad); + + input_sync(sc->touchpad); +} + static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *rd, int size) { @@ -1206,6 +1286,10 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, } dualshock4_parse_report(sc, rd, size); + + } else if ((sc->quirks & NSG_MRXU_REMOTE) && rd[0] == 0x02) { + nsg_mrxu_parse_report(sc, rd, size); + return 1; } if (sc->defer_initialization) { @@ -1263,7 +1347,7 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi, } static int sony_register_touchpad(struct sony_sc *sc, int touch_count, - int w, int h) + int w, int h, int touch_major, int touch_minor, int orientation) { size_t name_sz; char *name; @@ -1294,10 +1378,6 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count, snprintf(name, name_sz, "%s" DS4_TOUCHPAD_SUFFIX, sc->hdev->name); sc->touchpad->name = name; - ret = input_mt_init_slots(sc->touchpad, touch_count, INPUT_MT_POINTER); - if (ret < 0) - 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); @@ -1306,6 +1386,25 @@ static int sony_register_touchpad(struct sony_sc *sc, int touch_count, 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); + if (touch_major > 0) { + input_set_abs_params(sc->touchpad, ABS_MT_TOUCH_MAJOR, + 0, touch_major, 0, 0); + if (touch_minor > 0) + input_set_abs_params(sc->touchpad, ABS_MT_TOUCH_MINOR, + 0, touch_minor, 0, 0); + if (orientation > 0) + input_set_abs_params(sc->touchpad, ABS_MT_ORIENTATION, + 0, orientation, 0, 0); + } + + if (sc->quirks & NSG_MRXU_REMOTE) { + __set_bit(EV_REL, sc->touchpad->evbit); + } + + ret = input_mt_init_slots(sc->touchpad, touch_count, INPUT_MT_POINTER); + if (ret < 0) + goto err; + ret = input_register_device(sc->touchpad); if (ret < 0) goto err; @@ -2690,7 +2789,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(sc, 2, 1920, 942); + ret = sony_register_touchpad(sc, 2, 1920, 942, 0, 0, 0); if (ret) { hid_err(sc->hdev, "Unable to initialize multi-touch slots: %d\n", @@ -2721,6 +2820,20 @@ static int sony_input_configured(struct hid_device *hdev, } sony_init_output_report(sc, dualshock4_send_output_report); + } else if (sc->quirks & NSG_MRXU_REMOTE) { + /* + * The NSG-MRxU touchpad supports 2 touches and has a + * resolution of 1667x1868 + */ + ret = sony_register_touchpad(sc, 2, + NSG_MRXU_MAX_X, NSG_MRXU_MAX_Y, 15, 15, 1); + if (ret) { + hid_err(sc->hdev, + "Unable to initialize multi-touch slots: %d\n", + ret); + goto err_stop; + } + } else if (sc->quirks & MOTION_CONTROLLER) { sony_init_output_report(sc, motion_send_output_report); } else { @@ -2969,6 +3082,12 @@ static const struct hid_device_id sony_devices[] = { /* Nyko Core Controller for PS3 */ { HID_USB_DEVICE(USB_VENDOR_ID_SINO_LITE, USB_DEVICE_ID_SINO_LITE_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_USB | SINO_LITE_CONTROLLER }, + /* SMK-Link NSG-MR5U Remote Control */ + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR5U_REMOTE), + .driver_data = NSG_MR5U_REMOTE_BT }, + /* SMK-Link NSG-MR7U Remote Control */ + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR7U_REMOTE), + .driver_data = NSG_MR7U_REMOTE_BT }, { } }; MODULE_DEVICE_TABLE(hid, sony_devices);