aboutsummaryrefslogtreecommitdiff
path: root/SOURCES/steam-deck.patch
diff options
context:
space:
mode:
authorJan200101 <sentrycraft123@gmail.com>2024-04-06 17:05:32 +0200
committerJan200101 <sentrycraft123@gmail.com>2024-04-06 17:05:32 +0200
commit684f5ef56790771b425c7007c9dfcfbd8ea1a300 (patch)
tree118298a92be197f4a59d03cf2a5b447cbe9b9354 /SOURCES/steam-deck.patch
parentc0c9b770e4f24e17886587762c42194b6e524720 (diff)
downloadkernel-fsync-684f5ef56790771b425c7007c9dfcfbd8ea1a300.tar.gz
kernel-fsync-684f5ef56790771b425c7007c9dfcfbd8ea1a300.zip
kernel 6.8.2
Diffstat (limited to 'SOURCES/steam-deck.patch')
-rw-r--r--SOURCES/steam-deck.patch1527
1 files changed, 5 insertions, 1522 deletions
diff --git a/SOURCES/steam-deck.patch b/SOURCES/steam-deck.patch
index bbdb9ce..b118c46 100644
--- a/SOURCES/steam-deck.patch
+++ b/SOURCES/steam-deck.patch
@@ -225,7 +225,7 @@ diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 11d076cad8a2..d03c1e1d339f 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
-@@ -199,6 +199,7 @@
+@@ -200,6 +200,7 @@
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o
@@ -502,9 +502,9 @@ index 4fd2f92cd198..130a1c175dde 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -75,6 +75,7 @@
- obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
+ obj-$(CONFIG_LEDS_SUN50I_A100) += leds-sun50i-a100.o
+obj-$(CONFIG_LEDS_STEAMDECK) += leds-steamdeck.o
obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o
@@ -609,7 +609,7 @@ diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 290186e44e6b..4d444a9e2c1f 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
-@@ -202,4 +202,11 @@
+@@ -202,4 +202,12 @@
The DHC (Digital Home Hub) RTD series SoC contains a type c module.
This driver will detect the status of the type-c port.
@@ -620,12 +620,13 @@ index 290186e44e6b..4d444a9e2c1f 100644
+ Say Y here to enable support of USB Type C cable detection extcon
+ support on Steam Deck devices
+
++
endif
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 1b390d934ca9..1c7e217f29e4 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
-@@ -26,3 +26,4 @@
+@@ -25,3 +25,4 @@ obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o
obj-$(CONFIG_EXTCON_USBC_CROS_EC) += extcon-usbc-cros-ec.o
obj-$(CONFIG_EXTCON_USBC_TUSB320) += extcon-usbc-tusb320.o
obj-$(CONFIG_EXTCON_RTK_TYPE_C) += extcon-rtk-type-c.o
@@ -975,1523 +976,5 @@ index 0e504b3c2796..a60fa7db9141 100644
NULL
};
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Vicki Pfau <vi@endrift.com>
-Date: Thu, 30 Jun 2022 18:42:10 -0700
-Subject: [PATCH 01/10] USB: gadget: f_hid: Add Get-Feature report
-
-While the HID gadget implementation has been sufficient for devices that only
-use INTERRUPT transfers, the USB HID standard includes provisions for Set- and
-Get-Feature report CONTROL transfers that go over endpoint 0. These were
-previously impossible with the existing implementation, and would either send
-an empty reply, or stall out.
-
-As the feature is a standard part of USB HID, it stands to reason that devices
-would use it, and that the HID gadget should support it. This patch adds
-support for (polled) device-to-host Get-Feature reports through a new ioctl
-interface to the hidg class dev nodes.
-
-Signed-off-by: Vicki Pfau <vi@endrift.com>
-(cherry picked from commit 8437fa3861c7198a3e286f393c8637c4fc08d2bc)
-Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
----
- drivers/usb/gadget/function/f_hid.c | 121 ++++++++++++++++++++++++++--
- include/uapi/linux/usb/g_hid.h | 38 +++++++++
- include/uapi/linux/usb/gadgetfs.h | 2 +-
- 3 files changed, 154 insertions(+), 7 deletions(-)
- create mode 100644 include/uapi/linux/usb/g_hid.h
-
-diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
-index ea85e2c701a15..6fec92b5a0bd9 100644
---- a/drivers/usb/gadget/function/f_hid.c
-+++ b/drivers/usb/gadget/function/f_hid.c
-@@ -16,6 +16,7 @@
- #include <linux/wait.h>
- #include <linux/sched.h>
- #include <linux/usb/g_hid.h>
-+#include <uapi/linux/usb/g_hid.h>
-
- #include "u_f.h"
- #include "u_hid.h"
-@@ -75,6 +76,13 @@ struct f_hidg {
- wait_queue_head_t write_queue;
- struct usb_request *req;
-
-+ /* get report */
-+ struct usb_request *get_req;
-+ struct usb_hidg_report get_report;
-+ spinlock_t get_spinlock;
-+ bool get_pending;
-+ wait_queue_head_t get_queue;
-+
- struct device dev;
- struct cdev cdev;
- struct usb_function func;
-@@ -523,6 +531,64 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
- return status;
- }
-
-+
-+static int f_hidg_get_report(struct file *file, struct usb_hidg_report __user *buffer)
-+{
-+ struct f_hidg *hidg = file->private_data;
-+ struct usb_composite_dev *cdev = hidg->func.config->cdev;
-+
-+ int status = 0;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&hidg->get_spinlock, flags);
-+
-+#define GET_REPORT_COND (!hidg->get_pending)
-+
-+ while (!GET_REPORT_COND) {
-+ spin_unlock_irqrestore(&hidg->get_spinlock, flags);
-+
-+ if (file->f_flags & O_NONBLOCK)
-+ return -EAGAIN;
-+
-+ if (wait_event_interruptible_exclusive(hidg->get_queue,
-+ GET_REPORT_COND))
-+ return -ERESTARTSYS;
-+
-+ spin_lock_irqsave(&hidg->get_spinlock, flags);
-+ if (!hidg->get_pending) {
-+ spin_unlock_irqrestore(&hidg->get_spinlock, flags);
-+ return -EINVAL;
-+ }
-+ }
-+
-+ hidg->get_pending = true;
-+ spin_unlock_irqrestore(&hidg->get_spinlock, flags);
-+
-+ status = copy_from_user(&hidg->get_report, buffer,
-+ sizeof(struct usb_hidg_report));
-+ if (status != 0) {
-+ ERROR(cdev, "copy_from_user error\n");
-+ status = -EINVAL;
-+ }
-+
-+ spin_lock_irqsave(&hidg->get_spinlock, flags);
-+ hidg->get_pending = false;
-+ spin_unlock_irqrestore(&hidg->get_spinlock, flags);
-+
-+ wake_up(&hidg->get_queue);
-+ return status;
-+}
-+
-+static long f_hidg_ioctl(struct file *file, unsigned int code, unsigned long arg)
-+{
-+ switch (code) {
-+ case GADGET_HID_WRITE_GET_REPORT:
-+ return f_hidg_get_report(file, (struct usb_hidg_report __user *)arg);
-+ default:
-+ return -ENOTTY;
-+ }
-+}
-+
- static __poll_t f_hidg_poll(struct file *file, poll_table *wait)
- {
- struct f_hidg *hidg = file->private_data;
-@@ -548,6 +614,7 @@ static __poll_t f_hidg_poll(struct file *file, poll_table *wait)
- #undef WRITE_COND
- #undef READ_COND_SSREPORT
- #undef READ_COND_INTOUT
-+#undef GET_REPORT_COND
-
- static int f_hidg_release(struct inode *inode, struct file *fd)
- {
-@@ -640,6 +707,10 @@ static void hidg_ssreport_complete(struct usb_ep *ep, struct usb_request *req)
- wake_up(&hidg->read_queue);
- }
-
-+static void hidg_get_report_complete(struct usb_ep *ep, struct usb_request *req)
-+{
-+}
-+
- static int hidg_setup(struct usb_function *f,
- const struct usb_ctrlrequest *ctrl)
- {
-@@ -647,6 +718,8 @@ static int hidg_setup(struct usb_function *f,
- struct usb_composite_dev *cdev = f->config->cdev;
- struct usb_request *req = cdev->req;
- int status = 0;
-+ unsigned long flags;
-+ bool do_wake = false;
- __u16 value, length;
-
- value = __le16_to_cpu(ctrl->wValue);
-@@ -659,14 +732,29 @@ static int hidg_setup(struct usb_function *f,
- switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
- case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
- | HID_REQ_GET_REPORT):
-- VDBG(cdev, "get_report\n");
-+ VDBG(cdev, "get_report | wLength=%d\n", ctrl->wLength);
-
-- /* send an empty report */
-- length = min_t(unsigned, length, hidg->report_length);
-- memset(req->buf, 0x0, length);
-+ req = hidg->get_req;
-+ req->zero = 0;
-+ req->length = min_t(unsigned, length, hidg->report_length);
-+ status = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
-+ if (status < 0) {
-+ ERROR(cdev, "usb_ep_queue error on get_report %d\n",
-+ status);
-
-- goto respond;
-- break;
-+ spin_lock_irqsave(&hidg->get_spinlock, flags);
-+ if (hidg->get_pending) {
-+ hidg->get_pending = false;
-+ do_wake = true;
-+ }
-+ spin_unlock_irqrestore(&hidg->get_spinlock, flags);
-+
-+ if (do_wake) {
-+ wake_up(&hidg->get_queue);
-+ }
-+ }
-+
-+ return status;
-
- case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
- | HID_REQ_GET_PROTOCOL):
-@@ -800,6 +888,14 @@ static void hidg_disable(struct usb_function *f)
-
- hidg->req = NULL;
- spin_unlock_irqrestore(&hidg->write_spinlock, flags);
-+
-+ spin_lock_irqsave(&hidg->get_spinlock, flags);
-+ if (!hidg->get_pending) {
-+ usb_ep_free_request(f->config->cdev->gadget->ep0, hidg->get_req);
-+ hidg->get_pending = true;
-+ }
-+ hidg->get_req = NULL;
-+ spin_unlock_irqrestore(&hidg->get_spinlock, flags);
- }
-
- static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
-@@ -908,6 +1004,7 @@ static const struct file_operations f_hidg_fops = {
- .write = f_hidg_write,
- .read = f_hidg_read,
- .poll = f_hidg_poll,
-+ .unlocked_ioctl = f_hidg_ioctl,
- .llseek = noop_llseek,
- };
-
-@@ -918,6 +1015,14 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
- struct usb_string *us;
- int status;
-
-+ hidg->get_req = usb_ep_alloc_request(c->cdev->gadget->ep0, GFP_ATOMIC);
-+ if (!hidg->get_req)
-+ return -ENOMEM;
-+ hidg->get_req->buf = hidg->get_report.data;
-+ hidg->get_req->zero = 0;
-+ hidg->get_req->complete = hidg_get_report_complete;
-+ hidg->get_req->context = hidg;
-+
- /* maybe allocate device-global string IDs, and patch descriptors */
- us = usb_gstrings_attach(c->cdev, ct_func_strings,
- ARRAY_SIZE(ct_func_string_defs));
-@@ -1003,8 +1108,10 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
- hidg->write_pending = 1;
- hidg->req = NULL;
- spin_lock_init(&hidg->read_spinlock);
-+ spin_lock_init(&hidg->get_spinlock);
- init_waitqueue_head(&hidg->write_queue);
- init_waitqueue_head(&hidg->read_queue);
-+ init_waitqueue_head(&hidg->get_queue);
- INIT_LIST_HEAD(&hidg->completed_out_req);
-
- /* create char device */
-@@ -1021,6 +1128,8 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
- if (hidg->req != NULL)
- free_ep_req(hidg->in_ep, hidg->req);
-
-+ usb_ep_free_request(c->cdev->gadget->ep0, hidg->get_req);
-+
- return status;
- }
-
-diff --git a/include/uapi/linux/usb/g_hid.h b/include/uapi/linux/usb/g_hid.h
-new file mode 100644
-index 0000000000000..c6068b4863543
---- /dev/null
-+++ b/include/uapi/linux/usb/g_hid.h
-@@ -0,0 +1,38 @@
-+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
-+/*
-+ * g_hid.h -- Header file for USB HID gadget driver
-+ *
-+ * Copyright (C) 2022 Valve Software
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+
-+#ifndef __UAPI_LINUX_USB_G_HID_H
-+#define __UAPI_LINUX_USB_G_HID_H
-+
-+#include <linux/types.h>
-+
-+struct usb_hidg_report {
-+ __u16 length;
-+ __u8 data[512];
-+};
-+
-+/* The 'g' code is also used by gadgetfs and hid gadget ioctl requests.
-+ * Don't add any colliding codes to either driver, and keep
-+ * them in unique ranges (size 0x20 for now).
-+ */
-+#define GADGET_HID_WRITE_GET_REPORT _IOW('g', 0x42, struct usb_hidg_report)
-+
-+#endif /* __UAPI_LINUX_USB_G_HID_H */
-diff --git a/include/uapi/linux/usb/gadgetfs.h b/include/uapi/linux/usb/gadgetfs.h
-index 835473910a498..9754822b2a409 100644
---- a/include/uapi/linux/usb/gadgetfs.h
-+++ b/include/uapi/linux/usb/gadgetfs.h
-@@ -62,7 +62,7 @@ struct usb_gadgetfs_event {
- };
-
-
--/* The 'g' code is also used by printer gadget ioctl requests.
-+/* The 'g' code is also used by printer and hid gadget ioctl requests.
- * Don't add any colliding codes to either driver, and keep
- * them in unique ranges (size 0x20 for now).
- */
---
-2.41.0
-
-
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Vicki Pfau <vi@endrift.com>
-Date: Thu, 30 Jun 2022 18:43:10 -0700
-Subject: [PATCH 02/10] USB: gadget: f_hid: Add Set-Feature report
-
-While the HID gadget implementation has been sufficient for devices that only
-use INTERRUPT transfers, the USB HID standard includes provisions for Set- and
-Get-Feature report CONTROL transfers that go over endpoint 0. These were
-previously impossible with the existing implementation, and would either send
-an empty reply, or stall out.
-
-As the feature is a standard part of USB HID, it stands to reason that devices
-would use it, and that the HID gadget should support it. This patch adds
-support for host-to-device Set-Feature reports through a new ioctl
-interface to the hidg class dev nodes.
-
-Signed-off-by: Vicki Pfau <vi@endrift.com>
-(cherry picked from commit 3d82be0ec3aa3b947d9c927d7b06c433de15be8b)
-Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
----
- drivers/usb/gadget/function/f_hid.c | 110 ++++++++++++++++++++++++++--
- include/uapi/linux/usb/g_hid.h | 24 +-----
- 2 files changed, 106 insertions(+), 28 deletions(-)
-
-diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
-index 6fec92b5a0bd9..172cba91aded1 100644
---- a/drivers/usb/gadget/function/f_hid.c
-+++ b/drivers/usb/gadget/function/f_hid.c
-@@ -76,6 +76,11 @@ struct f_hidg {
- wait_queue_head_t write_queue;
- struct usb_request *req;
-
-+ /* set report */
-+ struct list_head completed_set_req;
-+ spinlock_t set_spinlock;
-+ wait_queue_head_t set_queue;
-+
- /* get report */
- struct usb_request *get_req;
- struct usb_hidg_report get_report;
-@@ -531,6 +536,54 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
- return status;
- }
-
-+static int f_hidg_set_report(struct file *file, struct usb_hidg_report __user *buffer)
-+{
-+ struct f_hidg *hidg = file->private_data;
-+ struct f_hidg_req_list *list;
-+ struct usb_request *req;
-+ unsigned long flags;
-+ unsigned short length;
-+ int status;
-+
-+ spin_lock_irqsave(&hidg->set_spinlock, flags);
-+
-+#define SET_REPORT_COND (!list_empty(&hidg->completed_set_req))
-+
-+ /* wait for at least one buffer to complete */
-+ while (!SET_REPORT_COND) {
-+ spin_unlock_irqrestore(&hidg->set_spinlock, flags);
-+ if (file->f_flags & O_NONBLOCK)
-+ return -EAGAIN;
-+
-+ if (wait_event_interruptible(hidg->set_queue, SET_REPORT_COND))
-+ return -ERESTARTSYS;
-+
-+ spin_lock_irqsave(&hidg->set_spinlock, flags);
-+ }
-+
-+ /* pick the first one */
-+ list = list_first_entry(&hidg->completed_set_req,
-+ struct f_hidg_req_list, list);
-+
-+ /*
-+ * Remove this from list to protect it from being free()
-+ * while host disables our function
-+ */
-+ list_del(&list->list);
-+
-+ req = list->req;
-+ spin_unlock_irqrestore(&hidg->set_spinlock, flags);
-+
-+ /* copy to user outside spinlock */
-+ length = min_t(unsigned short, sizeof(buffer->data), req->actual);
-+ status = copy_to_user(&buffer->length, &length, sizeof(buffer->length));
-+ if (!status) {
-+ status = copy_to_user(&buffer->data, req->buf, length);
-+ }
-+ kfree(list);
-+ free_ep_req(hidg->func.config->cdev->gadget->ep0, req);
-+ return status;
-+}
-
- static int f_hidg_get_report(struct file *file, struct usb_hidg_report __user *buffer)
- {
-@@ -582,6 +635,8 @@ static int f_hidg_get_report(struct file *file, struct usb_hidg_report __user *b
- static long f_hidg_ioctl(struct file *file, unsigned int code, unsigned long arg)
- {
- switch (code) {
-+ case GADGET_HID_READ_SET_REPORT:
-+ return f_hidg_set_report(file, (struct usb_hidg_report __user *)arg);
- case GADGET_HID_WRITE_GET_REPORT:
- return f_hidg_get_report(file, (struct usb_hidg_report __user *)arg);
- default:
-@@ -596,6 +651,7 @@ static __poll_t f_hidg_poll(struct file *file, poll_table *wait)
-
- poll_wait(file, &hidg->read_queue, wait);
- poll_wait(file, &hidg->write_queue, wait);
-+ poll_wait(file, &hidg->set_queue, wait);
-
- if (WRITE_COND)
- ret |= EPOLLOUT | EPOLLWRNORM;
-@@ -608,12 +664,16 @@ static __poll_t f_hidg_poll(struct file *file, poll_table *wait)
- ret |= EPOLLIN | EPOLLRDNORM;
- }
-
-+ if (SET_REPORT_COND)
-+ ret |= EPOLLPRI;
-+
- return ret;
- }
-
- #undef WRITE_COND
- #undef READ_COND_SSREPORT
- #undef READ_COND_INTOUT
-+#undef SET_REPORT_COND
- #undef GET_REPORT_COND
-
- static int f_hidg_release(struct inode *inode, struct file *fd)
-@@ -658,11 +718,19 @@ static void hidg_intout_complete(struct usb_ep *ep, struct usb_request *req)
-
- req_list->req = req;
-
-- spin_lock_irqsave(&hidg->read_spinlock, flags);
-- list_add_tail(&req_list->list, &hidg->completed_out_req);
-- spin_unlock_irqrestore(&hidg->read_spinlock, flags);
-+ if (ep == cdev->gadget->ep0) {
-+ spin_lock_irqsave(&hidg->set_spinlock, flags);
-+ list_add_tail(&req_list->list, &hidg->completed_set_req);
-+ spin_unlock_irqrestore(&hidg->set_spinlock, flags);
-
-- wake_up(&hidg->read_queue);
-+ wake_up(&hidg->set_queue);
-+ } else {
-+ spin_lock_irqsave(&hidg->read_spinlock, flags);
-+ list_add_tail(&req_list->list, &hidg->completed_out_req);
-+ spin_unlock_irqrestore(&hidg->read_spinlock, flags);
-+
-+ wake_up(&hidg->read_queue);
-+ }
- break;
- default:
- ERROR(cdev, "Set report failed %d\n", req->status);
-@@ -775,12 +843,27 @@ static int hidg_setup(struct usb_function *f,
- case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
- | HID_REQ_SET_REPORT):
- VDBG(cdev, "set_report | wLength=%d\n", ctrl->wLength);
-- if (hidg->use_out_ep)
-+ if (!hidg->use_out_ep) {
-+ req->complete = hidg_ssreport_complete;
-+ req->context = hidg;
-+ goto respond;
-+ }
-+ if (!length)
- goto stall;
-- req->complete = hidg_ssreport_complete;
-+ req = alloc_ep_req(cdev->gadget->ep0, GFP_ATOMIC);
-+ if (!req)
-+ return -ENOMEM;
-+ req->complete = hidg_intout_complete;
- req->context = hidg;
-- goto respond;
-- break;
-+ req->zero = 0;
-+ req->length = length;
-+ status = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
-+ if (status < 0) {
-+ ERROR(cdev, "usb_ep_queue error on set_report %d\n", status);
-+ free_ep_req(cdev->gadget->ep0, req);
-+ }
-+
-+ return status;
-
- case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
- | HID_REQ_SET_PROTOCOL):
-@@ -880,6 +963,14 @@ static void hidg_disable(struct usb_function *f)
- spin_unlock_irqrestore(&hidg->read_spinlock, flags);
- }
-
-+ spin_lock_irqsave(&hidg->set_spinlock, flags);
-+ list_for_each_entry_safe(list, next, &hidg->completed_set_req, list) {
-+ free_ep_req(f->config->cdev->gadget->ep0, list->req);
-+ list_del(&list->list);
-+ kfree(list);
-+ }
-+ spin_unlock_irqrestore(&hidg->set_spinlock, flags);
-+
- spin_lock_irqsave(&hidg->write_spinlock, flags);
- if (!hidg->write_pending) {
- free_ep_req(hidg->in_ep, hidg->req);
-@@ -1108,11 +1199,14 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
- hidg->write_pending = 1;
- hidg->req = NULL;
- spin_lock_init(&hidg->read_spinlock);
-+ spin_lock_init(&hidg->set_spinlock);
- spin_lock_init(&hidg->get_spinlock);
- init_waitqueue_head(&hidg->write_queue);
- init_waitqueue_head(&hidg->read_queue);
-+ init_waitqueue_head(&hidg->set_queue);
- init_waitqueue_head(&hidg->get_queue);
- INIT_LIST_HEAD(&hidg->completed_out_req);
-+ INIT_LIST_HEAD(&hidg->completed_set_req);
-
- /* create char device */
- cdev_init(&hidg->cdev, &f_hidg_fops);
-diff --git a/include/uapi/linux/usb/g_hid.h b/include/uapi/linux/usb/g_hid.h
-index c6068b4863543..54814c2c68d60 100644
---- a/include/uapi/linux/usb/g_hid.h
-+++ b/include/uapi/linux/usb/g_hid.h
-@@ -1,38 +1,22 @@
- /* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
--/*
-- * g_hid.h -- Header file for USB HID gadget driver
-- *
-- * Copyright (C) 2022 Valve Software
-- *
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License as published by
-- * the Free Software Foundation; either version 2 of the License, or
-- * (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful,
-- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- * GNU General Public License for more details.
-- *
-- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, write to the Free Software
-- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-- */
-
- #ifndef __UAPI_LINUX_USB_G_HID_H
- #define __UAPI_LINUX_USB_G_HID_H
-
- #include <linux/types.h>
-
-+#define HIDG_REPORT_SIZE_MAX 64
-+
- struct usb_hidg_report {
- __u16 length;
-- __u8 data[512];
-+ __u8 data[HIDG_REPORT_SIZE_MAX];
- };
-
- /* The 'g' code is also used by gadgetfs and hid gadget ioctl requests.
- * Don't add any colliding codes to either driver, and keep
- * them in unique ranges (size 0x20 for now).
- */
-+#define GADGET_HID_READ_SET_REPORT _IOR('g', 0x41, struct usb_hidg_report)
- #define GADGET_HID_WRITE_GET_REPORT _IOW('g', 0x42, struct usb_hidg_report)
-
- #endif /* __UAPI_LINUX_USB_G_HID_H */
---
-2.41.0
-
-
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Vicki Pfau <vi@endrift.com>
-Date: Tue, 29 Nov 2022 18:32:58 -0800
-Subject: [PATCH 03/10] HID: hid-steam: Update list of identifiers from SDL
-
-SDL includes a list of settings (registers), reports (cmds), and various other
-identifiers that were provided by Valve. This commit imports a significant
-chunk of that list as well as updating the guessed names and replacing a
-handful of magic constants. It also replaces bitmask definitions that used hex
-with the BIT macro.
-
-Signed-off-by: Vicki Pfau <vi@endrift.com>
----
- drivers/hid/hid-steam.c | 156 +++++++++++++++++++++++++++++++---------
- 1 file changed, 121 insertions(+), 35 deletions(-)
-
-diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
-index b110818fc9458..39a9bf3b7f77d 100644
---- a/drivers/hid/hid-steam.c
-+++ b/drivers/hid/hid-steam.c
-@@ -71,7 +71,7 @@ static LIST_HEAD(steam_devices);
-
- /*
- * Commands that can be sent in a feature report.
-- * Thanks to Valve for some valuable hints.
-+ * Thanks to Valve and SDL for some valuable hints.
- */
- #define STEAM_CMD_SET_MAPPINGS 0x80
- #define STEAM_CMD_CLEAR_MAPPINGS 0x81
-@@ -80,27 +80,98 @@ static LIST_HEAD(steam_devices);
- #define STEAM_CMD_GET_ATTRIB_LABEL 0x84
- #define STEAM_CMD_DEFAULT_MAPPINGS 0x85
- #define STEAM_CMD_FACTORY_RESET 0x86
--#define STEAM_CMD_WRITE_REGISTER 0x87
-+#define STEAM_CMD_SET_REGISTER 0x87
- #define STEAM_CMD_CLEAR_REGISTER 0x88
--#define STEAM_CMD_READ_REGISTER 0x89
-+#define STEAM_CMD_GET_REGISTER 0x89
- #define STEAM_CMD_GET_REGISTER_LABEL 0x8a
- #define STEAM_CMD_GET_REGISTER_MAX 0x8b
- #define STEAM_CMD_GET_REGISTER_DEFAULT 0x8c
- #define STEAM_CMD_SET_MODE 0x8d
--#define STEAM_CMD_DEFAULT_MOUSE 0x8e
--#define STEAM_CMD_FORCEFEEDBAK 0x8f
--#define STEAM_CMD_REQUEST_COMM_STATUS 0xb4
--#define STEAM_CMD_GET_SERIAL 0xae
-+#define STEAM_CMD_DEFAULT_REGISTER 0x8e
-+#define STEAM_CMD_HAPTIC_PULSE 0x8f
-+#define STEAM_CMD_TURN_OFF_CONTROLLER 0x9f
-+#define STEAM_CMD_GET_DEVICE_IFNO 0xa1
-+#define STEAM_CMD_CALIBRATE_TRACKPADS 0xa7
-+#define STEAM_CMD_SET_SERIAL 0xa9
-+#define STEAM_CMD_GET_TRACKPAD_CALIB 0xaa
-+#define STEAM_CMD_GET_TRACKPAD_FACTORY_CALIB 0xab
-+#define STEAM_CMD_GET_TRACKPAD_RAW_DATA 0xac
-+#define STEAM_CMD_ENABLE_PAIRING 0xad
-+#define STEAM_CMD_GET_STRING_ATTRIB 0xae
-+#define STEAM_CMD_RADIO_ERASE_RECORDS 0xaf
-+#define STEAM_CMD_RADIO_WRITE_RECORD 0xb0
-+#define STEAM_CMD_SET_DONGLE_SETTING 0xb1
-+#define STEAM_CMD_DONGLE_DISCONNECT_DEV 0xb2
-+#define STEAM_CMD_DONGLE_COMMIT_DEV 0xb3
-+#define STEAM_CMD_DONGLE_GET_STATE 0xb4
-+#define STEAM_CMD_CALIBRATE_GYRO 0xb5
-+#define STEAM_CMD_PLAY_AUDIO 0xb6
-+#define STEAM_CMD_AUDIO_UPDATE_START 0xb7
-+#define STEAM_CMD_AUDIO_UPDATE_DATA 0xb8
-+#define STEAM_CMD_AUDIO_UPDATE_COMPLETE 0xb9
-+#define STEAM_CMD_GET_CHIPID 0xba
-+#define STEAM_CMD_CALIBRATE_JOYSTICK 0xbf
-+#define STEAM_CMD_CALIBRATE_TRIGGERS 0xc0
-+#define STEAM_CMD_SET_AUDIO_MAPPING 0xc1
-+#define STEAM_CMD_CHECK_GYRO_FW_LOAD 0xc2
-+#define STEAM_CMD_CALIBRATE_ANALOG 0xc3
-+#define STEAM_CMD_DONGLE_GET_CONN_SLOTS 0xc4
-+#define STEAM_CMD_HAPTIC_CMD 0xea
- #define STEAM_CMD_HAPTIC_RUMBLE 0xeb
-
- /* Some useful register ids */
--#define STEAM_REG_LPAD_MODE 0x07
--#define STEAM_REG_RPAD_MODE 0x08
--#define STEAM_REG_RPAD_MARGIN 0x18
--#define STEAM_REG_LED 0x2d
--#define STEAM_REG_GYRO_MODE 0x30
--#define STEAM_REG_LPAD_CLICK_PRESSURE 0x34
--#define STEAM_REG_RPAD_CLICK_PRESSURE 0x35
-+#define STEAM_REG_MOUSE_SENSITIVITY 0x00
-+#define STEAM_REG_MOUSE_ACCELERATION 0x01
-+#define STEAM_REG_TRACKBALL_ROTATION_ANGLE 0x02
-+#define STEAM_REG_HAPTIC_INTENSITY 0x03
-+#define STEAM_REG_LEFT_GAMEPAD_STICK_ENABLED 0x04
-+#define STEAM_REG_RIGHT_GAMEPAD_STICK_ENABLED 0x05
-+#define STEAM_REG_USB_DEBUG_MODE 0x06
-+#define STEAM_REG_LEFT_TRACKPAD_MODE 0x07
-+#define STEAM_REG_RIGHT_TRACKPAD_MODE 0x08
-+#define STEAM_REG_MOUSE_POINTER_ENABLED 0x09
-+#define STEAM_REG_DPAD_DEADZONE 0x0a
-+#define STEAM_REG_MINIMUM_MOMENTUM_VEL 0x0b
-+#define STEAM_REG_MOMENTUM_DECAY_AMOUNT 0x0c
-+#define STEAM_REG_PAD_REL_MODE_TICKS_PER_PIXEL 0x0d
-+#define STEAM_REG_HAPTIC_INCREMENT 0x0e
-+#define STEAM_REG_DPAD_ANGLE_SIN 0x0f
-+#define STEAM_REG_DPAD_ANGLE_COS 0x10
-+#define STEAM_REG_MOMENTUM_VERTICAL_DIVISOR 0x11
-+#define STEAM_REG_MOMENTUM_MAXIMUM_VELOCITY 0x12
-+#define STEAM_REG_TRACKPAD_Z_ON 0x13
-+#define STEAM_REG_TRACKPAD_Z_OFF 0x14
-+#define STEAM_REG_SENSITIVY_SCALE_AMOUNT 0x15
-+#define STEAM_REG_LEFT_TRACKPAD_SECONDARY_MODE 0x16
-+#define STEAM_REG_RIGHT_TRACKPAD_SECONDARY_MODE 0x17
-+#define STEAM_REG_SMOOTH_ABSOLUTE_MOUSE 0x18
-+#define STEAM_REG_STEAMBUTTON_POWEROFF_TIME 0x19
-+#define STEAM_REG_TRACKPAD_OUTER_RADIUS 0x1b
-+#define STEAM_REG_TRACKPAD_Z_ON_LEFT 0x1c
-+#define STEAM_REG_TRACKPAD_Z_OFF_LEFT 0x1d
-+#define STEAM_REG_TRACKPAD_OUTER_SPIN_VEL 0x1e
-+#define STEAM_REG_TRACKPAD_OUTER_SPIN_RADIUS 0x1f
-+#define STEAM_REG_TRACKPAD_OUTER_SPIN_HORIZONTAL_ONLY 0x20
-+#define STEAM_REG_TRACKPAD_RELATIVE_MODE_DEADZONE 0x21
-+#define STEAM_REG_TRACKPAD_RELATIVE_MODE_MAX_VEL 0x22
-+#define STEAM_REG_TRACKPAD_RELATIVE_MODE_INVERT_Y 0x23
-+#define STEAM_REG_TRACKPAD_DOUBLE_TAP_BEEP_ENABLED 0x24
-+#define STEAM_REG_TRACKPAD_DOUBLE_TAP_BEEP_PERIOD 0x25
-+#define STEAM_REG_TRACKPAD_DOUBLE_TAP_BEEP_COUNT 0x26
-+#define STEAM_REG_TRACKPAD_OUTER_RADIUS_RELEASE_ON_TRANSITION 0x27
-+#define STEAM_REG_RADIAL_MODE_ANGLE 0x28
-+#define STEAM_REG_HAPTIC_INTENSITY_MOUSE_MODE 0x29
-+#define STEAM_REG_LEFT_DPAD_REQUIRES_CLICK 0x2a
-+#define STEAM_REG_RIGHT_DPAD_REQUIRES_CLICK 0x2b
-+#define STEAM_REG_LED_BASELINE_BRIGHTNESS 0x2c
-+#define STEAM_REG_LED_USER_BRIGHTNESS 0x2d
-+#define STEAM_REG_ENABLE_RAW_JOYSTICK 0x2e
-+#define STEAM_REG_ENABLE_FAST_SCAN 0x2f
-+#define STEAM_REG_GYRO_MODE 0x30
-+#define STEAM_REG_WIRELESS_PACKET_VERSION 0x31
-+#define STEAM_REG_SLEEP_INACTIVITY_TIMEOUT 0x32
-+#define STEAM_REG_LEFT_TRACKPAD_CLICK_PRESSURE 0x34
-+#define STEAM_REG_RIGHT_TRACKPAD_CLICK_PRESSURE 0x35
-
- /* Raw event identifiers */
- #define STEAM_EV_INPUT_DATA 0x01
-@@ -108,13 +179,28 @@ static LIST_HEAD(steam_devices);
- #define STEAM_EV_BATTERY 0x04
- #define STEAM_EV_DECK_INPUT_DATA 0x09
-
-+/* String attribute idenitifiers */
-+#define STEAM_ATTRIB_STR_BOARD_SERIAL 0x00
-+#define STEAM_ATTRIB_STR_UNIT_SERIAL 0x01
-+
- /* Values for GYRO_MODE (bitmask) */
--#define STEAM_GYRO_MODE_OFF 0x0000
--#define STEAM_GYRO_MODE_STEERING 0x0001
--#define STEAM_GYRO_MODE_TILT 0x0002
--#define STEAM_GYRO_MODE_SEND_ORIENTATION 0x0004
--#define STEAM_GYRO_MODE_SEND_RAW_ACCEL 0x0008
--#define STEAM_GYRO_MODE_SEND_RAW_GYRO 0x0010
-+#define STEAM_GYRO_MODE_OFF 0
-+#define STEAM_GYRO_MODE_STEERING BIT(0)
-+#define STEAM_GYRO_MODE_TILT BIT(1)
-+#define STEAM_GYRO_MODE_SEND_ORIENTATION BIT(2)
-+#define STEAM_GYRO_MODE_SEND_RAW_ACCEL BIT(3)
-+#define STEAM_GYRO_MODE_SEND_RAW_GYRO BIT(4)
-+
-+/* Trackpad modes */
-+#define STEAM_TRACKPAD_ABSOLUTE_MOUSE 0x00
-+#define STEAM_TRACKPAD_RELATIVE_MOUSE 0x01
-+#define STEAM_TRACKPAD_DPAD_FOUR_WAY_DISCRETE 0x02
-+#define STEAM_TRACKPAD_DPAD_FOUR_WAY_OVERLAP 0x03
-+#define STEAM_TRACKPAD_DPAD_EIGHT_WAY 0x04
-+#define STEAM_TRACKPAD_RADIAL_MODE 0x05
-+#define STEAM_TRACKPAD_ABSOLUTE_DPAD 0x06
-+#define STEAM_TRACKPAD_NONE 0x07
-+#define STEAM_TRACKPAD_GESTURE_KEYBOARD 0x08
-
- /* Other random constants */
- #define STEAM_SERIAL_LEN 10
-@@ -232,7 +318,7 @@ static int steam_write_registers(struct steam_device *steam,
- /* Send: 0x87 len (reg valLo valHi)* */
- u8 reg;
- u16 val;
-- u8 cmd[64] = {STEAM_CMD_WRITE_REGISTER, 0x00};
-+ u8 cmd[64] = {STEAM_CMD_SET_REGISTER, 0x00};
- int ret;
- va_list args;
-
-@@ -268,7 +354,7 @@ static int steam_get_serial(struct steam_device *steam)
- * Recv: 0xae 0x15 0x01 serialnumber (10 chars)
- */
- int ret;
-- u8 cmd[] = {STEAM_CMD_GET_SERIAL, 0x15, 0x01};
-+ u8 cmd[] = {STEAM_CMD_GET_STRING_ATTRIB, 0x15, STEAM_ATTRIB_STR_UNIT_SERIAL};
- u8 reply[3 + STEAM_SERIAL_LEN + 1];
-
- ret = steam_send_report(steam, cmd, sizeof(cmd));
-@@ -277,7 +363,7 @@ static int steam_get_serial(struct steam_device *steam)
- ret = steam_recv_report(steam, reply, sizeof(reply));
- if (ret < 0)
- return ret;
-- if (reply[0] != 0xae || reply[1] != 0x15 || reply[2] != 0x01)
-+ if (reply[0] != 0xae || reply[1] != 0x15 || reply[2] != STEAM_ATTRIB_STR_UNIT_SERIAL)
- return -EIO;
- reply[3 + STEAM_SERIAL_LEN] = 0;
- strscpy(steam->serial_no, reply + 3, sizeof(steam->serial_no));
-@@ -291,7 +377,7 @@ static int steam_get_serial(struct steam_device *steam)
- */
- static inline int steam_request_conn_status(struct steam_device *steam)
- {
-- return steam_send_report_byte(steam, STEAM_CMD_REQUEST_COMM_STATUS);
-+ return steam_send_report_byte(steam, STEAM_CMD_DONGLE_GET_STATE);
- }
-
- static inline int steam_haptic_rumble(struct steam_device *steam,
-@@ -339,9 +425,9 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
- /* enable esc, enter, cursors */
- steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MAPPINGS);
- /* enable mouse */
-- steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MOUSE);
-+ steam_send_report_byte(steam, STEAM_CMD_DEFAULT_REGISTER);
- steam_write_registers(steam,
-- STEAM_REG_RPAD_MARGIN, 0x01, /* enable margin */
-+ STEAM_REG_SMOOTH_ABSOLUTE_MOUSE, 0x01, /* enable smooth */
- 0);
-
- cancel_delayed_work_sync(&steam->heartbeat);
-@@ -351,11 +437,11 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
-
- if (steam->quirks & STEAM_QUIRK_DECK) {
- steam_write_registers(steam,
-- STEAM_REG_RPAD_MARGIN, 0x00, /* disable margin */
-- STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */
-- STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */
-- STEAM_REG_LPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */
-- STEAM_REG_RPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */
-+ STEAM_REG_SMOOTH_ABSOLUTE_MOUSE, 0x00, /* disable smooth */
-+ STEAM_REG_LEFT_TRACKPAD_MODE, STEAM_TRACKPAD_NONE, /* disable mouse */
-+ STEAM_REG_RIGHT_TRACKPAD_MODE, STEAM_TRACKPAD_NONE, /* disable mouse */
-+ STEAM_REG_LEFT_TRACKPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */
-+ STEAM_REG_RIGHT_TRACKPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */
- 0);
- /*
- * The Steam Deck has a watchdog that automatically enables
-@@ -365,9 +451,9 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
- schedule_delayed_work(&steam->heartbeat, 5 * HZ);
- } else {
- steam_write_registers(steam,
-- STEAM_REG_RPAD_MARGIN, 0x00, /* disable margin */
-- STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */
-- STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */
-+ STEAM_REG_SMOOTH_ABSOLUTE_MOUSE, 0x00, /* disable smooth */
-+ STEAM_REG_LEFT_TRACKPAD_MODE, STEAM_TRACKPAD_NONE, /* disable mouse */
-+ STEAM_REG_RIGHT_TRACKPAD_MODE, STEAM_TRACKPAD_NONE, /* disable mouse */
- 0);
- }
- }
-@@ -747,7 +833,7 @@ static void steam_lizard_mode_heartbeat(struct work_struct *work)
- if (!steam->client_opened && steam->client_hdev) {
- steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS);
- steam_write_registers(steam,
-- STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */
-+ STEAM_REG_RIGHT_TRACKPAD_MODE, STEAM_TRACKPAD_NONE, /* disable mouse */
- 0);
- schedule_delayed_work(&steam->heartbeat, 5 * HZ);
- }
---
-2.41.0
-
-
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Vicki Pfau <vi@endrift.com>
-Date: Wed, 16 Nov 2022 19:54:26 -0800
-Subject: [PATCH 04/10] HID: hid-steam: Add gamepad-only mode switched to by
- holding options
-
-Signed-off-by: Vicki Pfau <vi@endrift.com>
----
- drivers/hid/hid-steam.c | 72 +++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 72 insertions(+)
-
-diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
-index 39a9bf3b7f77d..0620046b142ef 100644
---- a/drivers/hid/hid-steam.c
-+++ b/drivers/hid/hid-steam.c
-@@ -202,6 +202,11 @@ static LIST_HEAD(steam_devices);
- #define STEAM_TRACKPAD_NONE 0x07
- #define STEAM_TRACKPAD_GESTURE_KEYBOARD 0x08
-
-+/* Pad identifiers for the deck */
-+#define STEAM_PAD_LEFT 0
-+#define STEAM_PAD_RIGHT 1
-+#define STEAM_PAD_BOTH 2
-+
- /* Other random constants */
- #define STEAM_SERIAL_LEN 10
-
-@@ -221,6 +226,9 @@ struct steam_device {
- u8 battery_charge;
- u16 voltage;
- struct delayed_work heartbeat;
-+ struct delayed_work mode_switch;
-+ bool did_mode_switch;
-+ bool gamepad_mode;
- struct work_struct rumble_work;
- u16 rumble_left;
- u16 rumble_right;
-@@ -380,6 +388,33 @@ static inline int steam_request_conn_status(struct steam_device *steam)
- return steam_send_report_byte(steam, STEAM_CMD_DONGLE_GET_STATE);
- }
-
-+/*
-+ * Send a haptic pulse to the trackpads
-+ * Duration and interval are measured in microseconds, count is the number
-+ * of pulses to send for duration time with interval microseconds between them
-+ * and gain is measured in decibels, ranging from -24 to +6
-+ */
-+static inline int steam_haptic_pulse(struct steam_device *steam, u8 pad,
-+ u16 duration, u16 interval, u16 count, u8 gain)
-+{
-+ u8 report[10] = {STEAM_CMD_HAPTIC_PULSE, 8};
-+
-+ /* Left and right are swapped on this report for legacy reasons */
-+ if (pad < STEAM_PAD_BOTH)
-+ pad ^= 1;
-+
-+ report[2] = pad;
-+ report[3] = duration & 0xFF;
-+ report[4] = duration >> 8;
-+ report[5] = interval & 0xFF;
-+ report[6] = interval >> 8;
-+ report[7] = count & 0xFF;
-+ report[8] = count >> 8;
-+ report[9] = gain;
-+
-+ return steam_send_report(steam, report, sizeof(report));
-+}
-+
- static inline int steam_haptic_rumble(struct steam_device *steam,
- u16 intensity, u16 left_speed, u16 right_speed,
- u8 left_gain, u8 right_gain)
-@@ -421,6 +456,9 @@ static int steam_play_effect(struct input_dev *dev, void *data,
-
- static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
- {
-+ if (steam->gamepad_mode)
-+ enable = false;
-+
- if (enable) {
- /* enable esc, enter, cursors */
- steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MAPPINGS);
-@@ -805,6 +843,29 @@ static void steam_work_connect_cb(struct work_struct *work)
- }
- }
-
-+static void steam_mode_switch_cb(struct work_struct *work)
-+{
-+ struct steam_device *steam = container_of(to_delayed_work(work),
-+ struct steam_device, mode_switch);
-+ steam->gamepad_mode = !steam->gamepad_mode;
-+ if (!lizard_mode)
-+ return;
-+
-+ mutex_lock(&steam->mutex);
-+ if (steam->gamepad_mode)
-+ steam_set_lizard_mode(steam, false);
-+ else if (!steam->client_opened)
-+ steam_set_lizard_mode(steam, lizard_mode);
-+ mutex_unlock(&steam->mutex);
-+
-+ steam_haptic_pulse(steam, STEAM_PAD_RIGHT, 0x190, 0, 1, 0);
-+ if (steam->gamepad_mode) {
-+ steam_haptic_pulse(steam, STEAM_PAD_LEFT, 0x14D, 0x14D, 0x2D, 0);
-+ } else {
-+ steam_haptic_pulse(steam, STEAM_PAD_LEFT, 0x1F4, 0x1F4, 0x1E, 0);
-+ }
-+}
-+
- static bool steam_is_valve_interface(struct hid_device *hdev)
- {
- struct hid_report_enum *rep_enum;
-@@ -977,6 +1038,7 @@ static int steam_probe(struct hid_device *hdev,
- mutex_init(&steam->mutex);
- steam->quirks = id->driver_data;
- INIT_WORK(&steam->work_connect, steam_work_connect_cb);
-+ INIT_DELAYED_WORK(&steam->mode_switch, steam_mode_switch_cb);
- INIT_LIST_HEAD(&steam->list);
- INIT_DEFERRABLE_WORK(&steam->heartbeat, steam_lizard_mode_heartbeat);
- INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb);
-@@ -1036,6 +1098,7 @@ static int steam_probe(struct hid_device *hdev,
- client_hdev_fail:
- cancel_work_sync(&steam->work_connect);
- cancel_delayed_work_sync(&steam->heartbeat);
-+ cancel_delayed_work_sync(&steam->mode_switch);
- cancel_work_sync(&steam->rumble_work);
- steam_alloc_fail:
- hid_err(hdev, "%s: failed with error %d\n",
-@@ -1059,6 +1122,7 @@ static void steam_remove(struct hid_device *hdev)
- cancel_delayed_work_sync(&steam->heartbeat);
- mutex_unlock(&steam->mutex);
- cancel_work_sync(&steam->work_connect);
-+ cancel_delayed_work_sync(&steam->mode_switch);
- if (steam->quirks & STEAM_QUIRK_WIRELESS) {
- hid_info(hdev, "Steam wireless receiver disconnected");
- }
-@@ -1393,6 +1457,14 @@ static void steam_do_deck_input_event(struct steam_device *steam,
- input_event(input, EV_KEY, BTN_BASE, !!(b14 & BIT(2)));
-
- input_sync(input);
-+
-+ if (!(b9 & BIT(6)) && steam->did_mode_switch) {
-+ steam->did_mode_switch = false;
-+ cancel_delayed_work_sync(&steam->mode_switch);
-+ } else if (!steam->client_opened && (b9 & BIT(6)) && !steam->did_mode_switch) {
-+ steam->did_mode_switch = true;
-+ schedule_delayed_work(&steam->mode_switch, 45 * HZ / 100);
-+ }
- }
-
- /*
---
-2.41.0
-
-
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Vicki Pfau <vi@endrift.com>
-Date: Mon, 8 May 2023 20:24:56 -0700
-Subject: [PATCH 05/10] HID: hid-steam: Clean up locking
-
-This cleans up the locking logic so that the spinlock is consistently used for
-access to a small handful of struct variables, and the mutex is exclusively and
-consistently used for ensuring that mutliple threads aren't trying to
-send/receive reports at the same time. Previously, only some report
-transactions were guarded by this mutex, potentially breaking atomicity. The
-mutex has been renamed to reflect this usage.
-
-Signed-off-by: Vicki Pfau <vi@endrift.com>
----
- drivers/hid/hid-steam.c | 148 ++++++++++++++++++++++++----------------
- 1 file changed, 90 insertions(+), 58 deletions(-)
-
-diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
-index 0620046b142ef..845ca71b8bd3a 100644
---- a/drivers/hid/hid-steam.c
-+++ b/drivers/hid/hid-steam.c
-@@ -214,7 +214,7 @@ struct steam_device {
- struct list_head list;
- spinlock_t lock;
- struct hid_device *hdev, *client_hdev;
-- struct mutex mutex;
-+ struct mutex report_mutex;
- bool client_opened;
- struct input_dev __rcu *input;
- unsigned long quirks;
-@@ -361,21 +361,26 @@ static int steam_get_serial(struct steam_device *steam)
- * Send: 0xae 0x15 0x01
- * Recv: 0xae 0x15 0x01 serialnumber (10 chars)
- */
-- int ret;
-+ int ret = 0;
- u8 cmd[] = {STEAM_CMD_GET_STRING_ATTRIB, 0x15, STEAM_ATTRIB_STR_UNIT_SERIAL};
- u8 reply[3 + STEAM_SERIAL_LEN + 1];
-
-+ mutex_lock(&steam->report_mutex);
- ret = steam_send_report(steam, cmd, sizeof(cmd));
- if (ret < 0)
-- return ret;
-+ goto out;
- ret = steam_recv_report(steam, reply, sizeof(reply));
- if (ret < 0)
-- return ret;
-- if (reply[0] != 0xae || reply[1] != 0x15 || reply[2] != STEAM_ATTRIB_STR_UNIT_SERIAL)
-- return -EIO;
-+ goto out;
-+ if (reply[0] != 0xae || reply[1] != 0x15 || reply[2] != STEAM_ATTRIB_STR_UNIT_SERIAL) {
-+ ret = -EIO;
-+ goto out;
-+ }
- reply[3 + STEAM_SERIAL_LEN] = 0;
- strscpy(steam->serial_no, reply + 3, sizeof(steam->serial_no));
-- return 0;
-+out:
-+ mutex_unlock(&steam->report_mutex);
-+ return ret;
- }
-
- /*
-@@ -385,7 +390,11 @@ static int steam_get_serial(struct steam_device *steam)
- */
- static inline int steam_request_conn_status(struct steam_device *steam)
- {
-- return steam_send_report_byte(steam, STEAM_CMD_DONGLE_GET_STATE);
-+ int ret;
-+ mutex_lock(&steam->report_mutex);
-+ ret = steam_send_report_byte(steam, STEAM_CMD_DONGLE_GET_STATE);
-+ mutex_unlock(&steam->report_mutex);
-+ return ret;
- }
-
- /*
-@@ -397,6 +406,7 @@ static inline int steam_request_conn_status(struct steam_device *steam)
- static inline int steam_haptic_pulse(struct steam_device *steam, u8 pad,
- u16 duration, u16 interval, u16 count, u8 gain)
- {
-+ int ret;
- u8 report[10] = {STEAM_CMD_HAPTIC_PULSE, 8};
-
- /* Left and right are swapped on this report for legacy reasons */
-@@ -412,13 +422,17 @@ static inline int steam_haptic_pulse(struct steam_device *steam, u8 pad,
- report[8] = count >> 8;
- report[9] = gain;
-
-- return steam_send_report(steam, report, sizeof(report));
-+ mutex_lock(&steam->report_mutex);
-+ ret = steam_send_report(steam, report, sizeof(report));
-+ mutex_unlock(&steam->report_mutex);
-+ return ret;
- }
-
- static inline int steam_haptic_rumble(struct steam_device *steam,
- u16 intensity, u16 left_speed, u16 right_speed,
- u8 left_gain, u8 right_gain)
- {
-+ int ret;
- u8 report[11] = {STEAM_CMD_HAPTIC_RUMBLE, 9};
-
- report[3] = intensity & 0xFF;
-@@ -430,7 +444,10 @@ static inline int steam_haptic_rumble(struct steam_device *steam,
- report[9] = left_gain;
- report[10] = right_gain;
-
-- return steam_send_report(steam, report, sizeof(report));
-+ mutex_lock(&steam->report_mutex);
-+ ret = steam_send_report(steam, report, sizeof(report));
-+ mutex_unlock(&steam->report_mutex);
-+ return ret;
- }
-
- static void steam_haptic_rumble_cb(struct work_struct *work)
-@@ -460,6 +477,7 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
- enable = false;
-
- if (enable) {
-+ mutex_lock(&steam->report_mutex);
- /* enable esc, enter, cursors */
- steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MAPPINGS);
- /* enable mouse */
-@@ -467,9 +485,11 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
- steam_write_registers(steam,
- STEAM_REG_SMOOTH_ABSOLUTE_MOUSE, 0x01, /* enable smooth */
- 0);
-+ mutex_unlock(&steam->report_mutex);
-
- cancel_delayed_work_sync(&steam->heartbeat);
- } else {
-+ mutex_lock(&steam->report_mutex);
- /* disable esc, enter, cursor */
- steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS);
-
-@@ -481,18 +501,19 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
- STEAM_REG_LEFT_TRACKPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */
- STEAM_REG_RIGHT_TRACKPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */
- 0);
-+ mutex_unlock(&steam->report_mutex);
- /*
- * The Steam Deck has a watchdog that automatically enables
- * lizard mode if it doesn't see any traffic for too long
- */
-- if (!work_busy(&steam->heartbeat.work))
-- schedule_delayed_work(&steam->heartbeat, 5 * HZ);
-+ schedule_delayed_work(&steam->heartbeat, 5 * HZ);
- } else {
- steam_write_registers(steam,
- STEAM_REG_SMOOTH_ABSOLUTE_MOUSE, 0x00, /* disable smooth */
- STEAM_REG_LEFT_TRACKPAD_MODE, STEAM_TRACKPAD_NONE, /* disable mouse */
- STEAM_REG_RIGHT_TRACKPAD_MODE, STEAM_TRACKPAD_NONE, /* disable mouse */
- 0);
-+ mutex_unlock(&steam->report_mutex);
- }
- }
- }
-@@ -500,22 +521,29 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
- static int steam_input_open(struct input_dev *dev)
- {
- struct steam_device *steam = input_get_drvdata(dev);
-+ unsigned long flags;
-+ bool set_lizard_mode;
-
-- mutex_lock(&steam->mutex);
-- if (!steam->client_opened && lizard_mode)
-+ spin_lock_irqsave(&steam->lock, flags);
-+ set_lizard_mode = !steam->client_opened && lizard_mode;
-+ spin_unlock_irqrestore(&steam->lock, flags);
-+ if (set_lizard_mode)
- steam_set_lizard_mode(steam, false);
-- mutex_unlock(&steam->mutex);
-+
- return 0;
- }
-
- static void steam_input_close(struct input_dev *dev)
- {
- struct steam_device *steam = input_get_drvdata(dev);
-+ unsigned long flags;
-+ bool set_lizard_mode;
-
-- mutex_lock(&steam->mutex);
-- if (!steam->client_opened && lizard_mode)
-+ spin_lock_irqsave(&steam->lock, flags);
-+ set_lizard_mode = !steam->client_opened && lizard_mode;
-+ spin_unlock_irqrestore(&steam->lock, flags);
-+ if (set_lizard_mode)
- steam_set_lizard_mode(steam, true);
-- mutex_unlock(&steam->mutex);
- }
-
- static enum power_supply_property steam_battery_props[] = {
-@@ -760,6 +788,7 @@ static int steam_register(struct steam_device *steam)
- {
- int ret;
- bool client_opened;
-+ unsigned long flags;
-
- /*
- * This function can be called several times in a row with the
-@@ -772,11 +801,9 @@ static int steam_register(struct steam_device *steam)
- * Unlikely, but getting the serial could fail, and it is not so
- * important, so make up a serial number and go on.
- */
-- mutex_lock(&steam->mutex);
- if (steam_get_serial(steam) < 0)
- strscpy(steam->serial_no, "XXXXXXXXXX",
- sizeof(steam->serial_no));
-- mutex_unlock(&steam->mutex);
-
- hid_info(steam->hdev, "Steam Controller '%s' connected",
- steam->serial_no);
-@@ -791,11 +818,11 @@ static int steam_register(struct steam_device *steam)
- mutex_unlock(&steam_devices_lock);
- }
-
-- mutex_lock(&steam->mutex);
-+ spin_lock_irqsave(&steam->lock, flags);
- client_opened = steam->client_opened;
-+ spin_unlock_irqrestore(&steam->lock, flags);
- if (!client_opened)
- steam_set_lizard_mode(steam, lizard_mode);
-- mutex_unlock(&steam->mutex);
-
- if (!client_opened)
- ret = steam_input_register(steam);
-@@ -847,16 +874,21 @@ static void steam_mode_switch_cb(struct work_struct *work)
- {
- struct steam_device *steam = container_of(to_delayed_work(work),
- struct steam_device, mode_switch);
-+ unsigned long flags;
-+ bool client_opened;
- steam->gamepad_mode = !steam->gamepad_mode;
- if (!lizard_mode)
- return;
-
-- mutex_lock(&steam->mutex);
- if (steam->gamepad_mode)
- steam_set_lizard_mode(steam, false);
-- else if (!steam->client_opened)
-- steam_set_lizard_mode(steam, lizard_mode);
-- mutex_unlock(&steam->mutex);
-+ else {
-+ spin_lock_irqsave(&steam->lock, flags);
-+ client_opened = steam->client_opened;
-+ spin_unlock_irqrestore(&steam->lock, flags);
-+ if (!client_opened)
-+ steam_set_lizard_mode(steam, lizard_mode);
-+ }
-
- steam_haptic_pulse(steam, STEAM_PAD_RIGHT, 0x190, 0, 1, 0);
- if (steam->gamepad_mode) {
-@@ -889,16 +921,21 @@ static void steam_lizard_mode_heartbeat(struct work_struct *work)
- {
- struct steam_device *steam = container_of(work, struct steam_device,
- heartbeat.work);
-+ bool client_opened;
-+ unsigned long flags;
-
-- mutex_lock(&steam->mutex);
-- if (!steam->client_opened && steam->client_hdev) {
-+ spin_lock_irqsave(&steam->lock, flags);
-+ client_opened = steam->client_opened;
-+ spin_unlock_irqrestore(&steam->lock, flags);
-+ if (!client_opened) {
-+ mutex_lock(&steam->report_mutex);
- steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS);
- steam_write_registers(steam,
- STEAM_REG_RIGHT_TRACKPAD_MODE, STEAM_TRACKPAD_NONE, /* disable mouse */
- 0);
-+ mutex_unlock(&steam->report_mutex);
- schedule_delayed_work(&steam->heartbeat, 5 * HZ);
- }
-- mutex_unlock(&steam->mutex);
- }
-
- static int steam_client_ll_parse(struct hid_device *hdev)
-@@ -921,10 +958,11 @@ static void steam_client_ll_stop(struct hid_device *hdev)
- static int steam_client_ll_open(struct hid_device *hdev)
- {
- struct steam_device *steam = hdev->driver_data;
-+ unsigned long flags;
-
-- mutex_lock(&steam->mutex);
-+ spin_lock_irqsave(&steam->lock, flags);
- steam->client_opened = true;
-- mutex_unlock(&steam->mutex);
-+ spin_unlock_irqrestore(&steam->lock, flags);
-
- steam_input_unregister(steam);
-
-@@ -939,14 +977,12 @@ static void steam_client_ll_close(struct hid_device *hdev)
- bool connected;
-
- spin_lock_irqsave(&steam->lock, flags);
-- connected = steam->connected;
-+ steam->client_opened = false;
-+ connected = steam->connected && !steam->client_opened;
- spin_unlock_irqrestore(&steam->lock, flags);
-
-- mutex_lock(&steam->mutex);
-- steam->client_opened = false;
- if (connected)
- steam_set_lizard_mode(steam, lizard_mode);
-- mutex_unlock(&steam->mutex);
-
- if (connected)
- steam_input_register(steam);
-@@ -1035,7 +1071,7 @@ static int steam_probe(struct hid_device *hdev,
- steam->hdev = hdev;
- hid_set_drvdata(hdev, steam);
- spin_lock_init(&steam->lock);
-- mutex_init(&steam->mutex);
-+ mutex_init(&steam->report_mutex);
- steam->quirks = id->driver_data;
- INIT_WORK(&steam->work_connect, steam_work_connect_cb);
- INIT_DELAYED_WORK(&steam->mode_switch, steam_mode_switch_cb);
-@@ -1043,13 +1079,6 @@ static int steam_probe(struct hid_device *hdev,
- INIT_DEFERRABLE_WORK(&steam->heartbeat, steam_lizard_mode_heartbeat);
- INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb);
-
-- steam->client_hdev = steam_create_client_hid(hdev);
-- if (IS_ERR(steam->client_hdev)) {
-- ret = PTR_ERR(steam->client_hdev);
-- goto client_hdev_fail;
-- }
-- steam->client_hdev->driver_data = steam;
--
- /*
- * With the real steam controller interface, do not connect hidraw.
- * Instead, create the client_hid and connect that.
-@@ -1058,10 +1087,6 @@ static int steam_probe(struct hid_device *hdev,
- if (ret)
- goto hid_hw_start_fail;
-
-- ret = hid_add_device(steam->client_hdev);
-- if (ret)
-- goto client_hdev_add_fail;
--
- ret = hid_hw_open(hdev);
- if (ret) {
- hid_err(hdev,
-@@ -1087,15 +1112,26 @@ static int steam_probe(struct hid_device *hdev,
- }
- }
-
-+ steam->client_hdev = steam_create_client_hid(hdev);
-+ if (IS_ERR(steam->client_hdev)) {
-+ ret = PTR_ERR(steam->client_hdev);
-+ goto client_hdev_fail;
-+ }
-+ steam->client_hdev->driver_data = steam;
-+
-+ ret = hid_add_device(steam->client_hdev);
-+ if (ret)
-+ goto client_hdev_add_fail;
-+
- return 0;
-
--input_register_fail:
--hid_hw_open_fail:
- client_hdev_add_fail:
- hid_hw_stop(hdev);
--hid_hw_start_fail:
-- hid_destroy_device(steam->client_hdev);
- client_hdev_fail:
-+ hid_destroy_device(steam->client_hdev);
-+input_register_fail:
-+hid_hw_open_fail:
-+hid_hw_start_fail:
- cancel_work_sync(&steam->work_connect);
- cancel_delayed_work_sync(&steam->heartbeat);
- cancel_delayed_work_sync(&steam->mode_switch);
-@@ -1115,14 +1151,12 @@ static void steam_remove(struct hid_device *hdev)
- return;
- }
-
-+ cancel_delayed_work_sync(&steam->heartbeat);
-+ cancel_delayed_work_sync(&steam->mode_switch);
-+ cancel_work_sync(&steam->work_connect);
- hid_destroy_device(steam->client_hdev);
-- mutex_lock(&steam->mutex);
- steam->client_hdev = NULL;
- steam->client_opened = false;
-- cancel_delayed_work_sync(&steam->heartbeat);
-- mutex_unlock(&steam->mutex);
-- cancel_work_sync(&steam->work_connect);
-- cancel_delayed_work_sync(&steam->mode_switch);
- if (steam->quirks & STEAM_QUIRK_WIRELESS) {
- hid_info(hdev, "Steam wireless receiver disconnected");
- }
-@@ -1597,10 +1631,8 @@ static int steam_param_set_lizard_mode(const char *val,
-
- mutex_lock(&steam_devices_lock);
- list_for_each_entry(steam, &steam_devices, list) {
-- mutex_lock(&steam->mutex);
- if (!steam->client_opened)
- steam_set_lizard_mode(steam, lizard_mode);
-- mutex_unlock(&steam->mutex);
- }
- mutex_unlock(&steam_devices_lock);
- return 0;
---
-2.41.0
-
-
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Vicki Pfau <vi@endrift.com>
-Date: Wed, 10 May 2023 17:27:12 -0700
-Subject: [PATCH 06/10] HID: hid-steam: Make client_opened a counter
-
-The client_opened variable was used to track if the hidraw was opened by any
-clients to silence keyboard/mouse events while opened. However, there was no
-counting of how many clients were opened, so opening two at the same time and
-then closing one would fool the driver into thinking it had no remaining opened
-clients.
-
-Signed-off-by: Vicki Pfau <vi@endrift.com>
----
- drivers/hid/hid-steam.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
-index 845ca71b8bd3a..0c2fe51b29bc1 100644
---- a/drivers/hid/hid-steam.c
-+++ b/drivers/hid/hid-steam.c
-@@ -215,7 +215,7 @@ struct steam_device {
- spinlock_t lock;
- struct hid_device *hdev, *client_hdev;
- struct mutex report_mutex;
-- bool client_opened;
-+ unsigned long client_opened;
- struct input_dev __rcu *input;
- unsigned long quirks;
- struct work_struct work_connect;
-@@ -787,7 +787,7 @@ static void steam_battery_unregister(struct steam_device *steam)
- static int steam_register(struct steam_device *steam)
- {
- int ret;
-- bool client_opened;
-+ unsigned long client_opened;
- unsigned long flags;
-
- /*
-@@ -961,7 +961,7 @@ static int steam_client_ll_open(struct hid_device *hdev)
- unsigned long flags;
-
- spin_lock_irqsave(&steam->lock, flags);
-- steam->client_opened = true;
-+ steam->client_opened++;
- spin_unlock_irqrestore(&steam->lock, flags);
-
- steam_input_unregister(steam);
-@@ -977,7 +977,7 @@ static void steam_client_ll_close(struct hid_device *hdev)
- bool connected;
-
- spin_lock_irqsave(&steam->lock, flags);
-- steam->client_opened = false;
-+ steam->client_opened--;
- connected = steam->connected && !steam->client_opened;
- spin_unlock_irqrestore(&steam->lock, flags);
-
-@@ -1156,7 +1156,7 @@ static void steam_remove(struct hid_device *hdev)
- cancel_work_sync(&steam->work_connect);
- hid_destroy_device(steam->client_hdev);
- steam->client_hdev = NULL;
-- steam->client_opened = false;
-+ steam->client_opened = 0;
- if (steam->quirks & STEAM_QUIRK_WIRELESS) {
- hid_info(hdev, "Steam wireless receiver disconnected");
- }
---
-2.41.0
-
-
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
-From: Vicki Pfau <vi@endrift.com>
-Date: Thu, 18 May 2023 18:00:35 -0700
-Subject: [PATCH 07/10] HID: hid-steam: Better handling of serial number length
-
-The second byte of the GET_STRING_ATTRIB report is a length, so we should set
-the size of the buffer to be the size we're actually requesting, and only
-reject the reply if the length out is nonsensical.
-
-Signed-off-by: Vicki Pfau <vi@endrift.com>
----
- drivers/hid/hid-steam.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
-index 0c2fe51b29bc1..92e3e1052fa42 100644
---- a/drivers/hid/hid-steam.c
-+++ b/drivers/hid/hid-steam.c
-@@ -208,7 +208,7 @@ static LIST_HEAD(steam_devices);
- #define STEAM_PAD_BOTH 2
-
- /* Other random constants */
--#define STEAM_SERIAL_LEN 10
-+#define STEAM_SERIAL_LEN 0x15
-
- struct steam_device {
- struct list_head list;
-@@ -359,10 +359,10 @@ static int steam_get_serial(struct steam_device *steam)
- {
- /*
- * Send: 0xae 0x15 0x01
-- * Recv: 0xae 0x15 0x01 serialnumber (10 chars)
-+ * Recv: 0xae 0x15 0x01 serialnumber
- */
- int ret = 0;
-- u8 cmd[] = {STEAM_CMD_GET_STRING_ATTRIB, 0x15, STEAM_ATTRIB_STR_UNIT_SERIAL};
-+ u8 cmd[] = {STEAM_CMD_GET_STRING_ATTRIB, sizeof(steam->serial_no), STEAM_ATTRIB_STR_UNIT_SERIAL};
- u8 reply[3 + STEAM_SERIAL_LEN + 1];
-
- mutex_lock(&steam->report_mutex);
-@@ -372,12 +372,12 @@ static int steam_get_serial(struct steam_device *steam)
- ret = steam_recv_report(steam, reply, sizeof(reply));
- if (ret < 0)
- goto out;
-- if (reply[0] != 0xae || reply[1] != 0x15 || reply[2] != STEAM_ATTRIB_STR_UNIT_SERIAL) {
-+ if (reply[0] != 0xae || reply[1] < 1 || reply[1] > sizeof(steam->serial_no) || reply[2] != STEAM_ATTRIB_STR_UNIT_SERIAL) {
- ret = -EIO;
- goto out;
- }
- reply[3 + STEAM_SERIAL_LEN] = 0;
-- strscpy(steam->serial_no, reply + 3, sizeof(steam->serial_no));
-+ strscpy(steam->serial_no, reply + 3, reply[1]);
- out:
- mutex_unlock(&steam->report_mutex);
- return ret;
--
2.41.0