From patchwork Mon Mar 11 21:19:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Boyle X-Patchwork-Id: 10848309 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EB0F2186E for ; Mon, 11 Mar 2019 21:35:16 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D340F28E26 for ; Mon, 11 Mar 2019 21:35:16 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C794E2912C; Mon, 11 Mar 2019 21:35:16 +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=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI 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 0BBFE290FE for ; Mon, 11 Mar 2019 21:35:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728318AbfCKVfP (ORCPT ); Mon, 11 Mar 2019 17:35:15 -0400 Received: from chris.boyle.name ([92.243.12.190]:45416 "EHLO chris.boyle.name" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728319AbfCKVfP (ORCPT ); Mon, 11 Mar 2019 17:35:15 -0400 Received: by chris.boyle.name (Postfix, from userid 1000) id 7B6BA3D4BB; Mon, 11 Mar 2019 22:19:13 +0100 (CET) Date: Mon, 11 Mar 2019 22:19:13 +0100 From: Chris Boyle To: linux-input@vger.kernel.org Cc: Jiri Kosina , Benjamin Tissoires Subject: [PATCH 1/3] drivers: hid: fix G940 axis/button mappings Message-ID: <20190311211913.GA25306@nova.chris.boyle.name> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) 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 Provide a complete map of axes and buttons for the Logitech Flight System G940, which fixes several issues: Stop conflating the stick X/Y axes with the mini-stick (hat) axes. This stops reported X jumping between stick X and hat X (likewise Y). Stop conflating the other three hat switches (non-mini-stick) with each other. This was caused by commit 190d7f02ce8e ("HID: input: do not increment usages when a duplicate is found") Report TRIM1 and TRIM2, previously ignored as unrecognised usage types. Report the MODE switch and hand sensor, previously ignored as they're in a vendor page. Signed-off-by: Chris Boyle --- drivers/hid/hid-lg.c | 100 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 5d419a95b6c2..d822cd98d677 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -7,6 +7,7 @@ * Copyright (c) 2006-2007 Jiri Kosina * Copyright (c) 2008 Jiri Slaby * Copyright (c) 2010 Hendrik Iben + * Copyright (c) 2019 Chris Boyle */ /* @@ -648,6 +649,101 @@ static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage, return 1; } +#define HID_SC_TRIM_AILERON (HID_UP_SIMULATION | 0xb1) +#define HID_SC_TRIM_PITCH (HID_UP_SIMULATION | 0xb9) +#define HID_SC_THROTTLE (HID_UP_SIMULATION | 0xbb) +#define HID_VENDOR_USAGE_1 (HID_UP_MSVENDOR | 0x01) + +#define map_abs(c) hid_map_usage(hi, usage, bit, max, EV_ABS, (c)) +#define map_key(c) hid_map_usage(hi, usage, bit, max, EV_KEY, (c)) + +static int lg_g940_mapping(struct hid_input *hi, struct hid_field *field, + struct hid_usage *usage, unsigned long **bit, + int *max) +{ + static const u16 button_map[] = { + /* trigger, red FIRE button, S1-3 (top) */ + BTN_TRIGGER, BTN_THUMB, BTN_BASE, BTN_BASE2, BTN_BASE3, + /* S4 (side), S5 (pinkie), press hat, trigger stage 2 */ + BTN_THUMB2, BTN_PINKIE, BTN_TOP2, BTN_TOP, + /* T1-4 (on throttle handle) */ + BTN_TRIGGER_HAPPY11, BTN_TRIGGER_HAPPY12, + BTN_TRIGGER_HAPPY13, BTN_TRIGGER_HAPPY14, + /* P1-8 (base of throttle, with LEDs) */ + BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY2, BTN_TRIGGER_HAPPY3, + BTN_TRIGGER_HAPPY4, BTN_TRIGGER_HAPPY5, BTN_TRIGGER_HAPPY6, + BTN_TRIGGER_HAPPY7, BTN_TRIGGER_HAPPY8 + }; + + static const u16 vendor_1_map[] = { + BTN_TRIGGER_HAPPY9, /* mode switch = 1 */ + BTN_TRIGGER_HAPPY10, /* mode switch = 3 */ + 0, 0, /* always 0? */ + 0, 0, /* pedals/throttle ok */ + 0, 0, /* always 1? */ + BTN_DEAD, /* hand sensor */ + 0, 0 /* always 0? / AC ok */ + }; + + switch (usage->hid) { + case HID_GD_X: case HID_GD_Y: + /* offset 0 is joystick motion; 96 is mini-stick/hat */ + map_abs(((field->report_offset > 0) ? ABS_TILT_X : ABS_X) + + usage->hid - HID_GD_X); + return 1; + case HID_GD_Z: /* rudder pedals */ + map_abs(ABS_RUDDER); + return 1; + case HID_GD_RX: /* right toe brake */ + map_abs(ABS_GAS); + return 1; + case HID_GD_RY: /* left toe brake */ + map_abs(ABS_BRAKE); + return 1; + case HID_GD_RZ: /* TRIM3 (rudder trim) */ + map_abs(ABS_RZ); + return 1; + case HID_GD_DIAL: /* index 0 is R2, 1 is R1 (front/right of throttle) */ + map_abs(usage->usage_index ? ABS_WHEEL : ABS_MISC); + return 1; + case HID_GD_HATSWITCH: /* offset 20 on stick, 24 & 28 on throttle */ + if (field->report_offset < 20 || field->report_offset > 28 || + field->report_offset % 4) + return 0; + usage->hat_min = field->logical_minimum; + usage->hat_max = field->logical_maximum; + map_abs(ABS_HAT0X + (field->report_offset - 20) / 2); + return 1; + case HID_SC_TRIM_AILERON: /* TRIM1 (pitch trim!) */ + map_abs(ABS_RX); + return 1; + case HID_SC_TRIM_PITCH: /* TRIM2 (aileron trim!) */ + map_abs(ABS_RY); + return 1; + case HID_SC_THROTTLE: /* two halves; index 0 is right-hand */ + map_abs(usage->usage_index ? ABS_Z : ABS_THROTTLE); + return 1; + default: + break; + } + + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON && + usage->usage_index < ARRAY_SIZE(button_map) && + button_map[usage->usage_index] != 0) { + map_key(button_map[usage->usage_index]); + return 1; + } + + if (usage->hid == HID_VENDOR_USAGE_1 && + usage->usage_index < ARRAY_SIZE(vendor_1_map) && + vendor_1_map[usage->usage_index] != 0) { + map_key(vendor_1_map[usage->usage_index]); + return 1; + } + + return 0; +} + static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) @@ -678,6 +774,10 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi, if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max)) return 1; + if (hdev->product == USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 && + lg_g940_mapping(hi, field, usage, bit, max)) + return 1; + if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON) return 0;