From: Rahul Rameshbabu <rrameshbabu@nvidia.com>
To: Fabio Baltieri <fabiobaltieri@chromium.org>
Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com>,
Jiri Kosina <jikos@kernel.org>,
linux-input@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v4] HID: hid-google-stadiaff: add support for Stadia force feedback
Date: Sun, 16 Jul 2023 15:11:12 -0700 [thread overview]
Message-ID: <87ttu3qzgf.fsf@nvidia.com> (raw)
In-Reply-To: <20230716204834.2879106-1-fabiobaltieri@chromium.org> (Fabio Baltieri's message of "Sun, 16 Jul 2023 20:48:34 +0000")
On Sun, 16 Jul, 2023 20:48:34 +0000 Fabio Baltieri <fabiobaltieri@chromium.org> wrote:
> Add a hid-google-stadiaff module to support rumble based force feedback
> on the Google Stadia controller. This works using the HID output
> endpoint exposed on both the USB and BLE interface.
>
> Signed-off-by: Fabio Baltieri <fabiobaltieri@chromium.org>
> ---
>
> Hi, this adds rumble support to the stadia controller using the input
> interface. Up to now this has only been implemented at application level
> using hidraw:
>
> https://source.chromium.org/chromium/chromium/src/+/main:device/gamepad/hid_haptic_gamepad.cc
>
> Tested with fftest, works both over USB and BLE.
>
> Changes from v3:
> - fixed an unintended use of dev_err instead of hid_err
> - fixed the driver name reference in the commit message
> - rebased so the change in hid-ids.h applies cleanly
>
> Changes from v2:
> - check stadiaff_init value at probe time and fail the probe if init
> fails
>
> Changes from v1:
> - renamed the module to hid-google-stadiaff.c
> - added locking for passing the state to the worker code
> - added a module removed check to prevent the work from rescheduling
>
> drivers/hid/Kconfig | 7 ++
> drivers/hid/Makefile | 1 +
> drivers/hid/hid-google-stadiaff.c | 158 ++++++++++++++++++++++++++++++
> drivers/hid/hid-ids.h | 1 +
> 4 files changed, 167 insertions(+)
> create mode 100644 drivers/hid/hid-google-stadiaff.c
>
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index e11c1c803676..545e81c8f359 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -412,6 +412,13 @@ config HID_GOOGLE_HAMMER
> help
> Say Y here if you have a Google Hammer device.
>
> +config HID_GOOGLE_STADIA_FF
> + tristate "Google Stadia force feedback"
> + select INPUT_FF_MEMLESS
> + help
> + Say Y here if you want to enable force feedback support for the Google
> + Stadia controller.
> +
> config HID_VIVALDI
> tristate "Vivaldi Keyboard"
> select HID_VIVALDI_COMMON
> diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
> index 7a9e160158f7..8a06d0f840bc 100644
> --- a/drivers/hid/Makefile
> +++ b/drivers/hid/Makefile
> @@ -55,6 +55,7 @@ obj-$(CONFIG_HID_GFRM) += hid-gfrm.o
> obj-$(CONFIG_HID_GLORIOUS) += hid-glorious.o
> obj-$(CONFIG_HID_VIVALDI_COMMON) += hid-vivaldi-common.o
> obj-$(CONFIG_HID_GOOGLE_HAMMER) += hid-google-hammer.o
> +obj-$(CONFIG_HID_GOOGLE_STADIA_FF) += hid-google-stadiaff.o
> obj-$(CONFIG_HID_VIVALDI) += hid-vivaldi.o
> obj-$(CONFIG_HID_GT683R) += hid-gt683r.o
> obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
> diff --git a/drivers/hid/hid-google-stadiaff.c b/drivers/hid/hid-google-stadiaff.c
> new file mode 100644
> index 000000000000..3731575562ab
> --- /dev/null
> +++ b/drivers/hid/hid-google-stadiaff.c
> @@ -0,0 +1,158 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Stadia controller rumble support.
> + *
> + * Copyright 2023 Google LLC
> + */
> +
> +#include <linux/hid.h>
> +#include <linux/input.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +
> +#include "hid-ids.h"
> +
> +#define STADIA_FF_REPORT_ID 5
> +
> +struct stadiaff_device {
> + struct hid_device *hid;
> + struct hid_report *report;
> + spinlock_t lock;
> + bool removed;
> + uint16_t strong_magnitude;
> + uint16_t weak_magnitude;
> + struct work_struct work;
> +};
> +
> +static void stadiaff_work(struct work_struct *work)
> +{
> + struct stadiaff_device *stadiaff =
> + container_of(work, struct stadiaff_device, work);
> + struct hid_field *rumble_field = stadiaff->report->field[0];
> + unsigned long flags;
> +
> + spin_lock_irqsave(&stadiaff->lock, flags);
> + rumble_field->value[0] = stadiaff->strong_magnitude;
> + rumble_field->value[1] = stadiaff->weak_magnitude;
> + spin_unlock_irqrestore(&stadiaff->lock, flags);
> +
> + hid_hw_request(stadiaff->hid, stadiaff->report, HID_REQ_SET_REPORT);
> +}
> +
> +static int stadiaff_play(struct input_dev *dev, void *data,
> + struct ff_effect *effect)
> +{
> + struct hid_device *hid = input_get_drvdata(dev);
> + struct stadiaff_device *stadiaff = hid_get_drvdata(hid);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&stadiaff->lock, flags);
> + if (!stadiaff->removed) {
> + stadiaff->strong_magnitude = effect->u.rumble.strong_magnitude;
> + stadiaff->weak_magnitude = effect->u.rumble.weak_magnitude;
> + schedule_work(&stadiaff->work);
> + }
> + spin_unlock_irqrestore(&stadiaff->lock, flags);
> +
> + return 0;
> +}
> +
> +static int stadiaff_init(struct hid_device *hid)
> +{
> + struct stadiaff_device *stadiaff;
> + struct hid_report *report;
> + struct hid_input *hidinput;
> + struct input_dev *dev;
> + int error;
> +
> + if (list_empty(&hid->inputs)) {
> + hid_err(hid, "no inputs found\n");
> + return -ENODEV;
> + }
> + hidinput = list_entry(hid->inputs.next, struct hid_input, list);
> + dev = hidinput->input;
> +
> + report = hid_validate_values(hid, HID_OUTPUT_REPORT,
> + STADIA_FF_REPORT_ID, 0, 2);
> + if (!report)
> + return -ENODEV;
> +
> + stadiaff = devm_kzalloc(&hid->dev, sizeof(struct stadiaff_device),
> + GFP_KERNEL);
> + if (!stadiaff)
> + return -ENOMEM;
> +
> + hid_set_drvdata(hid, stadiaff);
> +
> + input_set_capability(dev, EV_FF, FF_RUMBLE);
> +
> + error = input_ff_create_memless(dev, NULL, stadiaff_play);
> + if (error)
> + return error;
> +
> + stadiaff->removed = false;
> + stadiaff->hid = hid;
> + stadiaff->report = report;
> + INIT_WORK(&stadiaff->work, stadiaff_work);
> + spin_lock_init(&stadiaff->lock);
> +
> + hid_info(hid, "Force Feedback for Google Stadia controller\n");
> +
> + return 0;
> +}
> +
> +static int stadia_probe(struct hid_device *hdev, const struct hid_device_id *id)
> +{
> + int ret;
> +
> + ret = hid_parse(hdev);
> + if (ret) {
> + hid_err(hdev, "parse failed\n");
> + return ret;
> + }
> +
> + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
> + if (ret) {
> + hid_err(hdev, "hw start failed\n");
> + return ret;
> + }
> +
> + ret = stadiaff_init(hdev);
> + if (ret) {
> + hid_err(hdev, "force feedback init failed\n");
> + hid_hw_stop(hdev);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static void stadia_remove(struct hid_device *hid)
> +{
> + struct stadiaff_device *stadiaff = hid_get_drvdata(hid);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&stadiaff->lock, flags);
> + stadiaff->removed = true;
> + spin_unlock_irqrestore(&stadiaff->lock, flags);
> +
> + cancel_work_sync(&stadiaff->work);
> + hid_hw_stop(hid);
> +}
> +
> +static const struct hid_device_id stadia_devices[] = {
> + { HID_USB_DEVICE(USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_STADIA) },
> + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_STADIA) },
> + { }
> +};
> +MODULE_DEVICE_TABLE(hid, stadia_devices);
> +
> +static struct hid_driver stadia_driver = {
> + .name = "stadia",
> + .id_table = stadia_devices,
> + .probe = stadia_probe,
> + .remove = stadia_remove,
> +};
> +module_hid_driver(stadia_driver);
> +
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
> index 8a310f8ff20f..42c43d309f98 100644
> --- a/drivers/hid/hid-ids.h
> +++ b/drivers/hid/hid-ids.h
> @@ -531,6 +531,7 @@
> #define USB_DEVICE_ID_GOOGLE_DON 0x5050
> #define USB_DEVICE_ID_GOOGLE_EEL 0x5057
> #define USB_DEVICE_ID_GOOGLE_JEWEL 0x5061
> +#define USB_DEVICE_ID_GOOGLE_STADIA 0x9400
>
> #define USB_VENDOR_ID_GOTOP 0x08f2
> #define USB_DEVICE_ID_SUPER_Q2 0x007f
Reviewed-by: Rahul Rameshbabu <rrameshbabu@nvidia.com>
next prev parent reply other threads:[~2023-07-16 22:11 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-07-16 20:48 [PATCH v4] HID: hid-google-stadiaff: add support for Stadia force feedback Fabio Baltieri
2023-07-16 22:11 ` Rahul Rameshbabu [this message]
2023-08-14 9:35 ` Jiri Kosina
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87ttu3qzgf.fsf@nvidia.com \
--to=rrameshbabu@nvidia.com \
--cc=benjamin.tissoires@redhat.com \
--cc=fabiobaltieri@chromium.org \
--cc=jikos@kernel.org \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.