From patchwork Tue May 12 08:46:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Fran=C3=A7ois-Xavier_Carton?= X-Patchwork-Id: 11542341 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1D5D0912 for ; Tue, 12 May 2020 08:44:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F34F0206CC for ; Tue, 12 May 2020 08:44:30 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="N0xUr8D2" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725889AbgELIoa (ORCPT ); Tue, 12 May 2020 04:44:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40300 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1725776AbgELIoa (ORCPT ); Tue, 12 May 2020 04:44:30 -0400 Received: from mail-qk1-x744.google.com (mail-qk1-x744.google.com [IPv6:2607:f8b0:4864:20::744]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 16486C061A0C for ; Tue, 12 May 2020 01:44:30 -0700 (PDT) Received: by mail-qk1-x744.google.com with SMTP id z80so7232615qka.0 for ; Tue, 12 May 2020 01:44:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=ix6gM+Htn68tSfMWoX4yE+0urQFgTnLzLf5ZHOSJZ28=; b=N0xUr8D2jepQL6UisZ+R6VwVDR9jH3SxiyAUK7sSWKn599yFl4NPTS+bqTtC3quYFW uT88yEVZ8bGW+blnIg0fk4WggHZmQ1Nv8X8EGEdqyHzntD3fvA6k0vMX26aT+egRBmGJ WpZ521kGnvwaKk29vgZ8TXMdFB195CHaO1VSAuP4Sk9u3//lwMMekn71kHU6m1nNHFdW emIuxmHJDi7BevXdL5qLPXAZFnecuC2PEnzZ6lAF85lYVa8Yrng7zlcwUBiBaEV7obTV LudV44adRnEgDmwxjDzmajdM6/+cvH7lvfGkO8GN4egmy7T9JNH33Gbb3BpAOahJydXU Ld/g== 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:mime-version :content-transfer-encoding; bh=ix6gM+Htn68tSfMWoX4yE+0urQFgTnLzLf5ZHOSJZ28=; b=LWlFXLTicqBwfCmRz9Olj6MdoWTkTL/yy0qlqS8/s4I1HUPbntLahkY7SvEVTFpqGq oqiufLpC0u7IR+EV8HAymrKNiHpQUOOPTOoXw6Ff9fupyIlQWLtgW7OMOffXThuEA9Ng KeVoIKMX2XZGDTJvA6fkVT+p5ka4T9XjLIh+2hNwRiw72BhrTb2gUYSui0YkrIcCL04Q Ik4I3JzD141GkoBqSehk0gZ26B+uV28IDlS6YIogY69grIV/RGGTuDIqvcxz+ws3lIte dWa5SmELO1mKy0UFpjjmAs09tJG8LH3Ac67Fs15UotGeSpkIqtvJMje0Nu3TB9T9sHpO 3ckg== X-Gm-Message-State: AGi0Pubd8ubC/YgO1KpOcgNn+lbrvmChEQQfYligMP3tJV51Ol9G4CWm yeex8meW9dADcKxm7zjJhej7JkagJh4= X-Google-Smtp-Source: APiQypLu/WHlNhXg4St5kbdzUCVDAgPdVW6/sNHxCiksGe/sgc+f4+PsOJkiE+iPdRcFBDeaKJFaew== X-Received: by 2002:a37:27d6:: with SMTP id n205mr17480303qkn.149.1589273068631; Tue, 12 May 2020 01:44:28 -0700 (PDT) Received: from localhost ([2601:483:4200:9113:fdae:121b:56a3:4870]) by smtp.gmail.com with ESMTPSA id u7sm10793016qkc.1.2020.05.12.01.44.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 May 2020 01:44:28 -0700 (PDT) From: =?utf-8?q?Fran=C3=A7ois-Xavier_Carton?= To: linux-input@vger.kernel.org Cc: Ethan Lee , Bastien Nocera , Jiri Kosina , Benjamin Tissoires Subject: [PATCH v2 1/4] HID: gamecube-adapter: add nintendo gamecube adapter Date: Tue, 12 May 2020 10:46:13 +0200 Message-Id: <20200512084616.32158-1-fx.carton91@gmail.com> X-Mailer: git-send-email 2.26.2 MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org The hid-gamecube-adapter driver supports Nintendo Gamecube Controller Adapters. They are USB devices on which up to four Nintendo Gamecube Controllers can be plugged. The driver creates independent input devices as controllers are connected. Signed-off-by: François-Xavier Carton --- Changelog: v2: - Replaced calibration parameters by auto calibration using saved min/max values. - Only send rumble output reports if the value changed. - Only set rumble capability for normal controllers; wavebird controllers do not support rumble. - Send init command after suspend to get input reports again. MAINTAINERS | 6 + drivers/hid/Kconfig | 10 + drivers/hid/Makefile | 1 + drivers/hid/hid-gamecube-adapter.c | 386 +++++++++++++++++++++++++++++ drivers/hid/hid-ids.h | 1 + 5 files changed, 404 insertions(+) create mode 100644 drivers/hid/hid-gamecube-adapter.c diff --git a/MAINTAINERS b/MAINTAINERS index d5b1878f2815..585ddcf3a6dd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7025,6 +7025,12 @@ F: scripts/gcc-plugin.sh F: scripts/Makefile.gcc-plugins F: Documentation/kbuild/gcc-plugins.rst +GAMECUBE ADAPTER HID DRIVER +M: François-Xavier Carton +L: linux-input@vger.kernel.org +S: Maintained +F: drivers/hid/hid-gamecube-adapter* + GASKET DRIVER FRAMEWORK M: Rob Springer M: Todd Poynor diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7c89edbd6c5a..d49e261a74f6 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -350,6 +350,16 @@ config HID_EZKEY ---help--- Support for Ezkey BTC 8193 keyboard. +config HID_GAMECUBE_ADAPTER + tristate "Nintendo Gamecube Controller Adapter support" + depends on HID + depends on USB_HID + ---help--- + Support for the Nintendo Gamecube Controller Adapter. + + To compile this driver as a module, choose M here: the + module will be called hid-gamecube-adapter. + config HID_GEMBIRD tristate "Gembird Joypad" depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index d8ea4b8c95af..9cddc4d48db8 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_HID_ELAN) += hid-elan.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELO) += hid-elo.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o +obj-$(CONFIG_HID_GAMECUBE_ADAPTER) += hid-gamecube-adapter.o obj-$(CONFIG_HID_GEMBIRD) += hid-gembird.o obj-$(CONFIG_HID_GFRM) += hid-gfrm.o obj-$(CONFIG_HID_GLORIOUS) += hid-glorious.o diff --git a/drivers/hid/hid-gamecube-adapter.c b/drivers/hid/hid-gamecube-adapter.c new file mode 100644 index 000000000000..b1268339889e --- /dev/null +++ b/drivers/hid/hid-gamecube-adapter.c @@ -0,0 +1,386 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * HID driver for Nintendo Gamecube Controller Adapters + * + * Copyright (c) 2020 François-Xavier Carton + * + * This driver is based on: + * https://github.com/ToadKing/wii-u-gc-adapter + * drivers/hid/hid-wiimote-core.c + * drivers/hid/hid-steam.c + * + */ + +#include "hid-ids.h" +#include +#include +#include +#include +#include +#include "usbhid/usbhid.h" + +enum gamecube_output { + GC_CMD_INIT = 0x13 +}; + +enum gamecube_input { + GC_INPUT_REPORT = 0x21 +}; + +#define GC_INPUT_REPORT_SIZE 37 + +enum gamecube_ctrl_flags { + GC_FLAG_EXTRAPOWER = BIT(2), + GC_TYPE_NORMAL = BIT(4), + GC_TYPE_WAVEBIRD = BIT(5), + GC_TYPES = GC_TYPE_NORMAL | GC_TYPE_WAVEBIRD +}; + +enum gamecube_btn { + GC_BTN_START = BIT(0), + GC_BTN_Z = BIT(1), + GC_BTN_R = BIT(2), + GC_BTN_L = BIT(3), + GC_BTN_A = BIT(8), + GC_BTN_B = BIT(9), + GC_BTN_X = BIT(10), + GC_BTN_Y = BIT(11), + GC_BTN_DPAD_LEFT = BIT(12), + GC_BTN_DPAD_RIGHT = BIT(13), + GC_BTN_DPAD_DOWN = BIT(14), + GC_BTN_DPAD_UP = BIT(15), +}; + +struct gamecube_ctrl { + struct input_dev __rcu *input; + enum gamecube_ctrl_flags flags; + struct gamecube_adapter *adpt; + struct work_struct work_connect; + spinlock_t flags_lock; +}; + +struct gamecube_adapter { + struct gamecube_ctrl ctrls[4]; + struct hid_device *hdev; +}; + +static int gamecube_hid_send(struct hid_device *hdev, const u8 *data, size_t n) +{ + u8 *buf; + int ret; + + buf = kmemdup(data, n, GFP_KERNEL); + if (!buf) + return -ENOMEM; + ret = hid_hw_output_report(hdev, buf, n); + kfree(buf); + return ret; +} + +static int gamecube_send_cmd_init(struct hid_device *hdev) +{ + const u8 initcmd[] = {GC_CMD_INIT}; + return gamecube_hid_send(hdev, initcmd, sizeof(initcmd)); +} + +static const unsigned int gamecube_buttons[] = { + BTN_START, BTN_TR2, BTN_TR, BTN_TL, + BTN_SOUTH, BTN_WEST, BTN_EAST, BTN_NORTH, + BTN_DPAD_LEFT, BTN_DPAD_RIGHT, BTN_DPAD_DOWN, BTN_DPAD_UP +}; + +static const unsigned int gamecube_axes[] = { + ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_Z, ABS_RZ +}; + +static const char *gamecube_ctrl_name(u8 type) +{ + switch (type) { + case GC_TYPE_NORMAL: + return "Standard Gamecube Controller"; + case GC_TYPE_WAVEBIRD: + return "Wavebird Gamecube Controller"; + } + return NULL; +} + +static int gamecube_ctrl_create(struct gamecube_ctrl *ctrl, u8 type) +{ + struct input_dev *input; + struct hid_device *hdev = ctrl->adpt->hdev; + const char *name; + unsigned int i; + int ret; + + name = gamecube_ctrl_name(type); + if (!name) { + unsigned int num = ctrl - ctrl->adpt->ctrls; + hid_warn(hdev, "port %u: unknown controller plugged in\n", num + 1); + return -EINVAL; + } + + input = input_allocate_device(); + if (!input) + return -ENOMEM; + + input_set_drvdata(input, ctrl); + input->id.bustype = hdev->bus; + input->id.vendor = hdev->vendor; + input->id.product = hdev->product; + input->id.version = hdev->version; + input->name = name; + + for (i = 0; i < ARRAY_SIZE(gamecube_buttons); i++) + input_set_capability(input, EV_KEY, gamecube_buttons[i]); + for (i = 0; i < ARRAY_SIZE(gamecube_axes); i++) + input_set_abs_params(input, gamecube_axes[i], 0, 255, 0, 0); + + ret = input_register_device(input); + if (ret) + goto err_free_device; + + rcu_assign_pointer(ctrl->input, input); + return 0; + +err_free_device: + input_free_device(input); + return ret; +} + +static void gamecube_ctrl_destroy(struct gamecube_ctrl *ctrl) +{ + struct input_dev *input; + rcu_read_lock(); + input = rcu_dereference(ctrl->input); + rcu_read_unlock(); + if (!input) + return; + RCU_INIT_POINTER(ctrl->input, NULL); + synchronize_rcu(); + input_unregister_device(input); +} + +static void gamecube_work_connect_cb(struct work_struct *work) +{ + struct gamecube_ctrl *ctrl = container_of(work, struct gamecube_ctrl, work_connect); + struct input_dev *input; + unsigned long irq_flags; + unsigned int num = ctrl - ctrl->adpt->ctrls; + u8 type; + + spin_lock_irqsave(&ctrl->flags_lock, irq_flags); + type = ctrl->flags & GC_TYPES; + spin_unlock_irqrestore(&ctrl->flags_lock, irq_flags); + + rcu_read_lock(); + input = rcu_dereference(ctrl->input); + rcu_read_unlock(); + + if (type && input) { + hid_info(ctrl->adpt->hdev, "port %u: already connected\n", num + 1); + } else if (type) { + hid_info(ctrl->adpt->hdev, "port %u: controller plugged in\n", num + 1); + gamecube_ctrl_create(ctrl, type); + } else if (input) { + hid_info(ctrl->adpt->hdev, "port %u: controller unplugged\n", num + 1); + gamecube_ctrl_destroy(ctrl); + } +} + +static void gamecube_ctrl_handle_report(struct gamecube_ctrl *ctrl, u8 *data) +{ + struct input_dev *dev; + u16 btns = data[1] << 8 | data[2]; + u8 old_flags, new_flags = data[0]; + unsigned long irq_flags; + + spin_lock_irqsave(&ctrl->flags_lock, irq_flags); + old_flags = ctrl->flags; + ctrl->flags = new_flags; + spin_unlock_irqrestore(&ctrl->flags_lock, irq_flags); + + if ((new_flags & GC_TYPES) != (old_flags & GC_TYPES)) { + schedule_work(&ctrl->work_connect); + return; + } + if (!(new_flags & GC_TYPES)) + return; + + rcu_read_lock(); + dev = rcu_dereference(ctrl->input); + if (!dev) + goto unlock; + + input_report_key(dev, BTN_START, btns & GC_BTN_START); + input_report_key(dev, BTN_TR2, btns & GC_BTN_Z); + input_report_key(dev, BTN_TR, btns & GC_BTN_R); + input_report_key(dev, BTN_TL, btns & GC_BTN_L); + input_report_key(dev, BTN_SOUTH, btns & GC_BTN_A); + input_report_key(dev, BTN_WEST, btns & GC_BTN_B); + input_report_key(dev, BTN_EAST, btns & GC_BTN_X); + input_report_key(dev, BTN_NORTH, btns & GC_BTN_Y); + input_report_key(dev, BTN_DPAD_LEFT, btns & GC_BTN_DPAD_LEFT); + input_report_key(dev, BTN_DPAD_RIGHT, btns & GC_BTN_DPAD_RIGHT); + input_report_key(dev, BTN_DPAD_DOWN, btns & GC_BTN_DPAD_DOWN); + input_report_key(dev, BTN_DPAD_UP, btns & GC_BTN_DPAD_UP); + input_report_abs(dev, ABS_X, data[3]); + input_report_abs(dev, ABS_Y, 255 - data[4]); + input_report_abs(dev, ABS_RX, data[5]); + input_report_abs(dev, ABS_RY, 255 - data[6]); + input_report_abs(dev, ABS_Z, data[7]); + input_report_abs(dev, ABS_RZ, data[8]); + input_sync(dev); + +unlock: + rcu_read_unlock(); +} + +static int gamecube_hid_event(struct hid_device *hdev, + struct hid_report *report, u8 *raw_data, int size) +{ + struct gamecube_adapter *adpt = hid_get_drvdata(hdev); + unsigned int i; + + if (size < 1) + return -EINVAL; + if (size == GC_INPUT_REPORT_SIZE && raw_data[0] == GC_INPUT_REPORT) { + for (i = 0; i < 4; i++) + gamecube_ctrl_handle_report(adpt->ctrls + i, raw_data + 1 + 9 * i); + } else { + hid_warn(hdev, "unhandled event\n"); + } + + return 0; +} + +static struct gamecube_adapter *gamecube_adpt_create(struct hid_device *hdev) +{ + struct gamecube_adapter *adpt; + unsigned int i; + + adpt = kzalloc(sizeof(*adpt), GFP_KERNEL); + if (!adpt) + return NULL; + + adpt->hdev = hdev; + hid_set_drvdata(hdev, adpt); + + for (i = 0; i < 4; i++) { + adpt->ctrls[i].adpt = adpt; + INIT_WORK(&adpt->ctrls[i].work_connect, gamecube_work_connect_cb); + spin_lock_init(&adpt->ctrls[i].flags_lock); + } + + return adpt; +} + +static void gamecube_adpt_destroy(struct gamecube_adapter *adpt) +{ + unsigned int i; + + for (i = 0; i < 4; i++) { + gamecube_ctrl_destroy(adpt->ctrls + i); + } + hid_hw_close(adpt->hdev); + hid_hw_stop(adpt->hdev); + kfree(adpt); +} + +/* This is needed, as by default the URB buffer size is set to 38, which is + * one byte too long and will result in EOVERFLOW failures. + */ +static int gamecube_fixup_urb_in(struct gamecube_adapter *adpt) +{ + struct hid_device *hdev = adpt->hdev; + struct usbhid_device *usbhid; + + if (!hid_is_using_ll_driver(hdev, &usb_hid_driver)) + return -EINVAL; + usbhid = hdev->driver_data; + if (usbhid->urbin->transfer_buffer_length < GC_INPUT_REPORT_SIZE) + return -EINVAL; + usbhid->urbin->transfer_buffer_length = GC_INPUT_REPORT_SIZE; + return 0; +} + +static int gamecube_hid_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + struct gamecube_adapter *adpt; + int ret; + + adpt = gamecube_adpt_create(hdev); + if (!adpt) { + hid_err(hdev, "Can't alloc device\n"); + return -ENOMEM; + } + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "HID parse failed\n"); + goto err; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "HW start failed\n"); + goto err; + } + + ret = hid_hw_open(hdev); + if (ret) { + hid_err(hdev, "cannot start hardware I/O\n"); + goto err_stop; + } + + ret = gamecube_fixup_urb_in(adpt); + if (ret) { + hid_err(hdev, "failed to fix input URB\n"); + goto err_close; + } + + ret = gamecube_send_cmd_init(hdev); + if (ret < 0) { + hid_err(hdev, "failed to send init command\n"); + goto err_close; + } + + hid_info(hdev, "new adapter registered\n"); + return 0; + +err_close: + hid_hw_close(hdev); +err_stop: + hid_hw_stop(hdev); +err: + kfree(adpt); + return ret; +} + +static void gamecube_hid_remove(struct hid_device *hdev) +{ + struct gamecube_adapter *adpt = hid_get_drvdata(hdev); + + hid_info(hdev, "adapter removed\n"); + gamecube_adpt_destroy(adpt); +} + +static const struct hid_device_id gamecube_hid_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO, + USB_DEVICE_ID_NINTENDO_GAMECUBE_ADAPTER) }, + { } +}; +MODULE_DEVICE_TABLE(hid, gamecube_hid_devices); + +static struct hid_driver gamecube_hid_driver = { + .name = "gamecube-adapter", + .id_table = gamecube_hid_devices, + .probe = gamecube_hid_probe, + .remove = gamecube_hid_remove, + .raw_event = gamecube_hid_event, +}; +module_hid_driver(gamecube_hid_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("François-Xavier Carton "); +MODULE_DESCRIPTION("Driver for Nintendo Gamecube Controller Adapters"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b18b13147a6f..1ebea811ea3b 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -882,6 +882,7 @@ #define USB_VENDOR_ID_NINTENDO 0x057e #define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306 #define USB_DEVICE_ID_NINTENDO_WIIMOTE2 0x0330 +#define USB_DEVICE_ID_NINTENDO_GAMECUBE_ADAPTER 0x0337 #define USB_VENDOR_ID_NOVATEK 0x0603 #define USB_DEVICE_ID_NOVATEK_PCT 0x0600 From patchwork Tue May 12 08:46:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Fran=C3=A7ois-Xavier_Carton?= X-Patchwork-Id: 11542343 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7DAD714B4 for ; Tue, 12 May 2020 08:44:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5EF3D2072B for ; Tue, 12 May 2020 08:44:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="K+C/czIt" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725868AbgELIod (ORCPT ); Tue, 12 May 2020 04:44:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40302 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1728990AbgELIoc (ORCPT ); Tue, 12 May 2020 04:44:32 -0400 Received: from mail-qk1-x741.google.com (mail-qk1-x741.google.com [IPv6:2607:f8b0:4864:20::741]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1AA2FC061A0C for ; Tue, 12 May 2020 01:44:31 -0700 (PDT) Received: by mail-qk1-x741.google.com with SMTP id b6so11648775qkh.11 for ; Tue, 12 May 2020 01:44:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ZBg2JvBUuK9lhnmNPNdV7qJYa4iJD3u/t2MGwMiaIpA=; b=K+C/czIteS41ccvjzXhfIzCqwcrnWoKXhBjyQv9WfnDoV7Ht1FXq1eeLowRajuYHWC CEtpDhzpkHNexc+acU98HAPPRbwKD9uabvRwpK3AzzLu3EFT1Kc3XfarfnS+l9cTbHNg I8gPbXNqWt9hyWphgGT+7j8kqaO7SmFBARWMr57lD11NNRSSZiGTQcHfCivgiH60Smn3 OLDarzr5yen8/c00d5IoM9KH6dWOjWfWUB0P4t2P7hYQpE2fBeMDxROYpSnEdCGon2le n9IWqG3mqee2e3glkqzREKjQ6QUbnOuKFDuYFI3WWyJh+fb8fExE98Kw15yQAmxLeMDy WnhA== 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:mime-version:content-transfer-encoding; bh=ZBg2JvBUuK9lhnmNPNdV7qJYa4iJD3u/t2MGwMiaIpA=; b=Th3H4inYbD2KRtZUIHxhp7Y7Duj0d19UN9gpOyTt31ldxQQyI1rPINDbGKJ/DeVpDS nnxdhhUsHqsO7HKk0Y+fnkB00thWXpXjeqv0uJ74XosmR1AIypY6m5H/LUYJ5ZXCkIvk vQw6uwaYhwgG0GTL1k3ALW0DWmADuyAgRtTfY0DNRc1ixejN1m9CPGRNgIQZeGxC+NpC 7cCjYzpB/7PwLqptOe8IKTTuZN8KqWb/CB1g/7ejLwXlByYw0yeIl4yymDKCgsrkY4Us GWkBuwQL2uqKOvX40e9b8GRnaWSA10X0L9RHRMdWiC2GCzMXS9Gb0x20tqzZkPIAwHCD 48vw== X-Gm-Message-State: AGi0PuZhj9inP/TYqnQnJ+jcO2ylC7TeZr2qOmC1Y6Y+yNSqqM9UN16n 46RX+OGpD79+FUDu5GAx6YlNOF0fdDw= X-Google-Smtp-Source: APiQypIOJlb/p/QoNfzGc+rEoNz6EAyxkcu5AKKkC0lmTsHgVUmIvKAuMeB9NjXHlsoMRHTHqiYo/g== X-Received: by 2002:a37:b44:: with SMTP id 65mr21096063qkl.368.1589273070132; Tue, 12 May 2020 01:44:30 -0700 (PDT) Received: from localhost ([2601:483:4200:9113:fdae:121b:56a3:4870]) by smtp.gmail.com with ESMTPSA id 74sm10658643qke.71.2020.05.12.01.44.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 May 2020 01:44:29 -0700 (PDT) From: =?utf-8?q?Fran=C3=A7ois-Xavier_Carton?= To: linux-input@vger.kernel.org Cc: Ethan Lee , Bastien Nocera , Jiri Kosina , Benjamin Tissoires Subject: [PATCH v2 2/4] HID: gamecube-adapter: add rumble support Date: Tue, 12 May 2020 10:46:14 +0200 Message-Id: <20200512084616.32158-2-fx.carton91@gmail.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200512084616.32158-1-fx.carton91@gmail.com> References: <20200512084616.32158-1-fx.carton91@gmail.com> MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org Add rumble support for the hid-gamecube-adapter driver. Rumble is reported with a single output report for all four controllers. Signed-off-by: François-Xavier Carton --- drivers/hid/Kconfig | 8 ++++ drivers/hid/hid-gamecube-adapter.c | 75 +++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index d49e261a74f6..324981308783 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -360,6 +360,14 @@ config HID_GAMECUBE_ADAPTER To compile this driver as a module, choose M here: the module will be called hid-gamecube-adapter. +config HID_GAMECUBE_ADAPTER_FF + bool "Nintendo Gamecube Controller Adapter force feedback" + depends on HID_GAMECUBE_ADAPTER + select INPUT_FF_MEMLESS + ---help--- + Say Y here if you want to enable force feedback support for Nintendo + Gamecube Controller Adapters. + config HID_GEMBIRD tristate "Gembird Joypad" depends on HID diff --git a/drivers/hid/hid-gamecube-adapter.c b/drivers/hid/hid-gamecube-adapter.c index b1268339889e..028ce005c9e3 100644 --- a/drivers/hid/hid-gamecube-adapter.c +++ b/drivers/hid/hid-gamecube-adapter.c @@ -20,7 +20,8 @@ #include "usbhid/usbhid.h" enum gamecube_output { - GC_CMD_INIT = 0x13 + GC_CMD_INIT = 0x13, + GC_CMD_RUMBLE = 0x11 }; enum gamecube_input { @@ -54,14 +55,18 @@ enum gamecube_btn { struct gamecube_ctrl { struct input_dev __rcu *input; enum gamecube_ctrl_flags flags; + u8 rumble; struct gamecube_adapter *adpt; struct work_struct work_connect; spinlock_t flags_lock; + spinlock_t rumble_lock; }; struct gamecube_adapter { struct gamecube_ctrl ctrls[4]; struct hid_device *hdev; + struct work_struct work_rumble; + u8 rumble; }; static int gamecube_hid_send(struct hid_device *hdev, const u8 *data, size_t n) @@ -83,6 +88,59 @@ static int gamecube_send_cmd_init(struct hid_device *hdev) return gamecube_hid_send(hdev, initcmd, sizeof(initcmd)); } +#ifdef CONFIG_HID_GAMECUBE_ADAPTER_FF +static int gamecube_send_cmd_rumble(struct gamecube_adapter *adpt) +{ + struct gamecube_ctrl *ctrls = adpt->ctrls; + u8 cmd[5] = {GC_CMD_RUMBLE}; + unsigned long flags; + unsigned int i; + int rumble_ok; + u8 rumble = 0; + + for (i = 0; i < 4; i++) { + spin_lock_irqsave(&ctrls[i].flags_lock, flags); + rumble_ok = (ctrls[i].flags & GC_TYPES) && (ctrls[i].flags & GC_FLAG_EXTRAPOWER); + spin_unlock_irqrestore(&ctrls[i].flags_lock, flags); + if (!rumble_ok) + continue; + spin_lock_irqsave(&ctrls[i].rumble_lock, flags); + cmd[i + 1] = ctrls[i].rumble; + rumble |= (ctrls[i].rumble & 1U) << i; + spin_unlock_irqrestore(&ctrls[i].rumble_lock, flags); + } + if (rumble == adpt->rumble) + return 0; + adpt->rumble = rumble; + return gamecube_hid_send(adpt->hdev, cmd, sizeof(cmd)); +} + +static void gamecube_rumble_worker(struct work_struct *work) +{ + struct gamecube_adapter *adpt = container_of(work, struct gamecube_adapter, + work_rumble); + + gamecube_send_cmd_rumble(adpt); +} + +static int gamecube_rumble_play(struct input_dev *dev, void *data, + struct ff_effect *eff) +{ + struct gamecube_ctrl *ctrl = input_get_drvdata(dev); + struct gamecube_adapter *adpt = ctrl->adpt; + unsigned long flags; + + if (eff->type != FF_RUMBLE) + return 0; + + spin_lock_irqsave(&ctrl->rumble_lock, flags); + ctrl->rumble = (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude); + spin_unlock_irqrestore(&ctrl->rumble_lock, flags); + schedule_work(&adpt->work_rumble); + return 0; +} +#endif + static const unsigned int gamecube_buttons[] = { BTN_START, BTN_TR2, BTN_TR, BTN_TL, BTN_SOUTH, BTN_WEST, BTN_EAST, BTN_NORTH, @@ -134,6 +192,13 @@ static int gamecube_ctrl_create(struct gamecube_ctrl *ctrl, u8 type) input_set_capability(input, EV_KEY, gamecube_buttons[i]); for (i = 0; i < ARRAY_SIZE(gamecube_axes); i++) input_set_abs_params(input, gamecube_axes[i], 0, 255, 0, 0); +#ifdef CONFIG_HID_GAMECUBE_ADAPTER_FF + if (type == GC_TYPE_NORMAL) { + input_set_capability(input, EV_FF, FF_RUMBLE); + if (input_ff_create_memless(input, NULL, gamecube_rumble_play)) + hid_warn(hdev, "failed to create ff memless\n"); + } +#endif ret = input_register_device(input); if (ret) @@ -269,7 +334,12 @@ static struct gamecube_adapter *gamecube_adpt_create(struct hid_device *hdev) adpt->ctrls[i].adpt = adpt; INIT_WORK(&adpt->ctrls[i].work_connect, gamecube_work_connect_cb); spin_lock_init(&adpt->ctrls[i].flags_lock); + spin_lock_init(&adpt->ctrls[i].rumble_lock); } +#ifdef CONFIG_HID_GAMECUBE_ADAPTER_FF + INIT_WORK(&adpt->work_rumble, gamecube_rumble_worker); + adpt->rumble = 0; +#endif return adpt; } @@ -281,6 +351,9 @@ static void gamecube_adpt_destroy(struct gamecube_adapter *adpt) for (i = 0; i < 4; i++) { gamecube_ctrl_destroy(adpt->ctrls + i); } +#ifdef CONFIG_HID_GAMECUBE_ADAPTER_FF + cancel_work_sync(&adpt->work_rumble); +#endif hid_hw_close(adpt->hdev); hid_hw_stop(adpt->hdev); kfree(adpt); From patchwork Tue May 12 08:46:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Fran=C3=A7ois-Xavier_Carton?= X-Patchwork-Id: 11542345 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9C8C317EA for ; Tue, 12 May 2020 08:44:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 829A220714 for ; Tue, 12 May 2020 08:44:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mDpnNCEn" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729047AbgELIod (ORCPT ); Tue, 12 May 2020 04:44:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40308 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1725868AbgELIoc (ORCPT ); Tue, 12 May 2020 04:44:32 -0400 Received: from mail-qv1-xf41.google.com (mail-qv1-xf41.google.com [IPv6:2607:f8b0:4864:20::f41]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 35CC5C061A0E for ; Tue, 12 May 2020 01:44:32 -0700 (PDT) Received: by mail-qv1-xf41.google.com with SMTP id a4so2734128qvj.3 for ; Tue, 12 May 2020 01:44:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=00WvLbTJMjzGOjQ1qyn39xJkeLMGMArXryJMzS4F5zY=; b=mDpnNCEnntbLPPOqEyH++3/v5S5J8wunGMhsoJVsL22OejsGVS546FRlpJ/VplJ8L3 jQjf2ybkjHeL+fLuOENkaACwE6kYLFbxCD1VOaxkW/7YP2187N+D3Zrg1ZmG2Gznetrs 0triVvO+pdFjxRZCL7dFF3wk7UvSvEl0SWXKK+6acharKJ/yWwpwINbT37aZUgkJFp+A 1o0Mh7DbjIkcOPLuo84/SFLFc7jILNhLNjvwcWVJ8Wjs+zCXodizzI6opo/s2dkE4NII DRP0JCxi9ZxI1CXTgqzJvidc2gYJvWV45yVAR2wSiRpnz5gNJlyUnhdSmR6yihi2glrP CSeg== 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:mime-version:content-transfer-encoding; bh=00WvLbTJMjzGOjQ1qyn39xJkeLMGMArXryJMzS4F5zY=; b=LtvCRgH7t2LPTDkqJX0macJk7iiU9sbS4khA6bHYdOF9UACSJ75yHMR0J341apBnIF jY0J039tBYqN0MJWuDGjx/Y1asrqfapaL8rjH+i9VqDPACxoL4MDZgoQkvrm3KTlsxGv re43A9wpA8o7KyT17PeidV4GzEKOp3SJyUJyZaMvdncwpgrDlYwPZe9MXg1yueQt82Qa OC18DGYYvy2ksmcXIvyOBAx1BiXehzu5hQPqIdzErp7gSI+Nbt7aBIThO521O0v0EjLs MUM5X/CvRJqAH6pCld/7TRA264468AbEbkTZH76Ng9FYLQffkaDG5uLzSTtrwfGlzSk+ sO8g== X-Gm-Message-State: AOAM5334S/l0C+SgOeN5hOecMZEeMOZo6I/uCMRYhjb7EAnJALKuXe95 KbE/JA6Smx7JVqBm/HArPhxGq1p6CPQ= X-Google-Smtp-Source: ABdhPJw+hkU5Uw33Fax9t1um9bR8Aezcnp4X/N3e/0iSeeNpvb/55SET58l46JiJuxzF+MK9K9EFzQ== X-Received: by 2002:a05:6214:18f3:: with SMTP id ep19mr832894qvb.45.1589273071364; Tue, 12 May 2020 01:44:31 -0700 (PDT) Received: from localhost ([2601:483:4200:9113:fdae:121b:56a3:4870]) by smtp.gmail.com with ESMTPSA id d7sm10610990qkk.26.2020.05.12.01.44.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 May 2020 01:44:31 -0700 (PDT) From: =?utf-8?q?Fran=C3=A7ois-Xavier_Carton?= To: linux-input@vger.kernel.org Cc: Ethan Lee , Bastien Nocera , Jiri Kosina , Benjamin Tissoires Subject: [PATCH v2 3/4] HID: gamecube-adapter: add auto calibration Date: Tue, 12 May 2020 10:46:15 +0200 Message-Id: <20200512084616.32158-3-fx.carton91@gmail.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200512084616.32158-1-fx.carton91@gmail.com> References: <20200512084616.32158-1-fx.carton91@gmail.com> MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org The axes do not cover the full 0-255 range, with different limit values for each axis. The minimal and maximal values are recorded for each axis and the values are remapped from that range to 0-255. Signed-off-by: François-Xavier Carton --- drivers/hid/hid-gamecube-adapter.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-gamecube-adapter.c b/drivers/hid/hid-gamecube-adapter.c index 028ce005c9e3..efcbd8f27b67 100644 --- a/drivers/hid/hid-gamecube-adapter.c +++ b/drivers/hid/hid-gamecube-adapter.c @@ -55,6 +55,8 @@ enum gamecube_btn { struct gamecube_ctrl { struct input_dev __rcu *input; enum gamecube_ctrl_flags flags; + u8 axis_min[6]; + u8 axis_max[6]; u8 rumble; struct gamecube_adapter *adpt; struct work_struct work_connect; @@ -258,6 +260,7 @@ static void gamecube_ctrl_handle_report(struct gamecube_ctrl *ctrl, u8 *data) u16 btns = data[1] << 8 | data[2]; u8 old_flags, new_flags = data[0]; unsigned long irq_flags; + unsigned int i; spin_lock_irqsave(&ctrl->flags_lock, irq_flags); old_flags = ctrl->flags; @@ -265,6 +268,11 @@ static void gamecube_ctrl_handle_report(struct gamecube_ctrl *ctrl, u8 *data) spin_unlock_irqrestore(&ctrl->flags_lock, irq_flags); if ((new_flags & GC_TYPES) != (old_flags & GC_TYPES)) { + // Reset min/max values. The default values were obtained empirically + for (i = 0; i < 6; i++) { + ctrl->axis_min[i] = 45; // max across all axes of min values + ctrl->axis_max[i] = 215; // min across all axes of max values + } schedule_work(&ctrl->work_connect); return; } @@ -288,12 +296,15 @@ static void gamecube_ctrl_handle_report(struct gamecube_ctrl *ctrl, u8 *data) input_report_key(dev, BTN_DPAD_RIGHT, btns & GC_BTN_DPAD_RIGHT); input_report_key(dev, BTN_DPAD_DOWN, btns & GC_BTN_DPAD_DOWN); input_report_key(dev, BTN_DPAD_UP, btns & GC_BTN_DPAD_UP); - input_report_abs(dev, ABS_X, data[3]); - input_report_abs(dev, ABS_Y, 255 - data[4]); - input_report_abs(dev, ABS_RX, data[5]); - input_report_abs(dev, ABS_RY, 255 - data[6]); - input_report_abs(dev, ABS_Z, data[7]); - input_report_abs(dev, ABS_RZ, data[8]); + for (i = 0; i < 6; i++) { + u8 a, b, v = data[3 + i]; + a = ctrl->axis_min[i] = min(ctrl->axis_min[i], v); + b = ctrl->axis_max[i] = max(ctrl->axis_max[i], v); + v = 255U * (v - a) / (b - a); + if (gamecube_axes[i] == ABS_Y || gamecube_axes[i] == ABS_RY) + v = 255U - v; + input_report_abs(dev, gamecube_axes[i], v); + } input_sync(dev); unlock: From patchwork Tue May 12 08:46:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Fran=C3=A7ois-Xavier_Carton?= X-Patchwork-Id: 11542347 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B758D912 for ; Tue, 12 May 2020 08:44:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A051E20714 for ; Tue, 12 May 2020 08:44:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="eezuuE0g" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729152AbgELIoe (ORCPT ); Tue, 12 May 2020 04:44:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40310 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1729081AbgELIod (ORCPT ); Tue, 12 May 2020 04:44:33 -0400 Received: from mail-qt1-x842.google.com (mail-qt1-x842.google.com [IPv6:2607:f8b0:4864:20::842]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4BEF4C061A0C for ; Tue, 12 May 2020 01:44:33 -0700 (PDT) Received: by mail-qt1-x842.google.com with SMTP id c24so3939603qtw.7 for ; Tue, 12 May 2020 01:44:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=1knqQDXtEJ5kXrNk6aN/d00f8DxBySu2hc2sGXn/2SA=; b=eezuuE0g938wCvoqLUZSfnoEqlWoVorMH2TtHBb7hYUrff3WAZ+nBIS0ePKKpAhD0s uLwxVXvfh+5qAC49bJG2HgViR0e14H1LxYy+hyqtNXhb2SnUl9dQ1bmkNZA8f5NF3QS9 CYRiLW/923xntNOAOA5fP4MI8cekAJiiLRG3iZJluURJ1eyJhKAntJ/L3YRu3s2iPx1j 5i974Z0+frRTCz1qrPWleCZgQrerDvWwrUCL7hPYz1WgmIucO2CHu1yN8fi2fuMbCBIi FvB7ppzw3cCiH5sqFef+cRoFPthOabxFP7sl92Z0FoISefAfeoSM2AeY8FKCZ6VXLSZa uAhw== 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:mime-version:content-transfer-encoding; bh=1knqQDXtEJ5kXrNk6aN/d00f8DxBySu2hc2sGXn/2SA=; b=I8iCn4I72oGgWWtf7iAuYc47eIc6K4OJUz+BW2Co8kmpsXpsstcxYmJTtHjYGJdVBa RVoiXm2YMOidwvBLz21qQV8kU+w6RYPIQrddEgmLtTurdhlZy4XpzP4MxJILKNCdArM7 mBx5Os4vs4Zq4TB4Wr4hWRiLkPU0DV6o19cSsjx6DELXR7u8KnuoJrfgfcZ27R4tBd+K 5yJvy730eyRfEbs/pDU4+BFi86TdKm9TrVD4kuxXta9jeL9ITCadQGZRf2RIeccfYzu7 6CJRN5RUNT2MniugqfluFFY6BG/D9mkP8n2ImwrcKPIqj4Vf/fGGDL0FuvVP+Hco5zSZ LBkw== X-Gm-Message-State: AOAM5314cBfu3myhRz1LSIAwAk/Wg4UqbqQyFG1Xac8q2Q6/ZeHPYFjr e7CELwtCcnpoWET9KSsQHqUkezgocak= X-Google-Smtp-Source: ABdhPJz3FVHsquEYOUWNUnpXu3kkuuk9Rr42S9sEXwhY/QeBNPtXS1mkr2zuaEZQ9ZPk9CMmMyQpkQ== X-Received: by 2002:ac8:1967:: with SMTP id g36mr2069744qtk.332.1589273072493; Tue, 12 May 2020 01:44:32 -0700 (PDT) Received: from localhost ([2601:483:4200:9113:fdae:121b:56a3:4870]) by smtp.gmail.com with ESMTPSA id a124sm10766311qkf.93.2020.05.12.01.44.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 12 May 2020 01:44:32 -0700 (PDT) From: =?utf-8?q?Fran=C3=A7ois-Xavier_Carton?= To: linux-input@vger.kernel.org Cc: Ethan Lee , Bastien Nocera , Jiri Kosina , Benjamin Tissoires Subject: [PATCH v2 4/4] HID: gamecube-adapter: restore input after suspend Date: Tue, 12 May 2020 10:46:16 +0200 Message-Id: <20200512084616.32158-4-fx.carton91@gmail.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200512084616.32158-1-fx.carton91@gmail.com> References: <20200512084616.32158-1-fx.carton91@gmail.com> MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org Send the init command after suspend, so that we get input reports again. Signed-off-by: François-Xavier Carton --- drivers/hid/hid-gamecube-adapter.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/hid/hid-gamecube-adapter.c b/drivers/hid/hid-gamecube-adapter.c index efcbd8f27b67..11d3e483f0c1 100644 --- a/drivers/hid/hid-gamecube-adapter.c +++ b/drivers/hid/hid-gamecube-adapter.c @@ -441,6 +441,14 @@ static int gamecube_hid_probe(struct hid_device *hdev, return ret; } +#ifdef CONFIG_PM +static int gamecube_resume(struct hid_device *hdev) +{ + gamecube_send_cmd_init(hdev); + return 0; +} +#endif + static void gamecube_hid_remove(struct hid_device *hdev) { struct gamecube_adapter *adpt = hid_get_drvdata(hdev); @@ -462,6 +470,9 @@ static struct hid_driver gamecube_hid_driver = { .probe = gamecube_hid_probe, .remove = gamecube_hid_remove, .raw_event = gamecube_hid_event, +#ifdef CONFIG_PM + .reset_resume = gamecube_resume, +#endif }; module_hid_driver(gamecube_hid_driver);