diff options
author | Jan200101 <sentrycraft123@gmail.com> | 2024-04-20 14:41:10 +0200 |
---|---|---|
committer | Jan200101 <sentrycraft123@gmail.com> | 2024-04-20 14:41:10 +0200 |
commit | a16cd9ea29d449a3ad5a34c563541628feb5b87c (patch) | |
tree | b24e97ca2c37b6e5b871bc1422f021f1d80d06c5 /SOURCES/steam-deck.patch | |
parent | ee6cb1dc945d3cd3642059e64672d11a7662935a (diff) | |
download | kernel-fsync-a16cd9ea29d449a3ad5a34c563541628feb5b87c.tar.gz kernel-fsync-a16cd9ea29d449a3ad5a34c563541628feb5b87c.zip |
kernel 6.7.12 update
Diffstat (limited to 'SOURCES/steam-deck.patch')
-rw-r--r-- | SOURCES/steam-deck.patch | 1557 |
1 files changed, 62 insertions, 1495 deletions
diff --git a/SOURCES/steam-deck.patch b/SOURCES/steam-deck.patch index bbdb9ce..0630ca3 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 @@ -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,89 @@ 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. +From: Matthew Schwartz <njtransit215@gmail.com> Mon Sep 17 00:00:00 2001 +From: Andrey Smirnov <andrew.smirnov@gmail.com> +Date: Mon, 20 Nov 2023 05:42:03 -0800 +Subject: [PATCH] leds-steamdeck: Add support for LED birghtness multiplier -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. +Add support for LED birghtness multiplier exposed via custom sysfs +attribute (led_brightness_multiplier). -Signed-off-by: Vicki Pfau <vi@endrift.com> -(cherry picked from commit 8437fa3861c7198a3e286f393c8637c4fc08d2bc) +Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> +(cherry picked from commit c4ea057992e189ec8821cde3a65e2cc0529a5088) +(cherry picked from commit e90fb9bec45c15c0c541ce60b994bab3922ddadf) 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 + drivers/leds/leds-steamdeck.c | 49 +++++++++++++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) -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; - } +diff --git a/drivers/leds/leds-steamdeck.c b/drivers/leds/leds-steamdeck.c +index 686500b8de736..ada9fffc0a420 100644 +--- a/drivers/leds/leds-steamdeck.c ++++ b/drivers/leds/leds-steamdeck.c +@@ -16,6 +16,54 @@ struct steamdeck_led { + struct led_classdev cdev; + }; -+ -+static int f_hidg_get_report(struct file *file, struct usb_hidg_report __user *buffer) ++static ssize_t led_brightness_multiplier_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) +{ -+ 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; -+ } ++ struct led_classdev *cdev = dev_get_drvdata(dev); ++ struct steamdeck_led *sd = container_of(cdev, struct steamdeck_led, ++ cdev); ++ unsigned long long led_brightness_multiplier; + -+ spin_lock_irqsave(&hidg->get_spinlock, flags); -+ hidg->get_pending = false; -+ spin_unlock_irqrestore(&hidg->get_spinlock, flags); ++ if (ACPI_FAILURE(acpi_evaluate_integer(sd->adev->handle, ++ "GLDM", ++ NULL, ++ &led_brightness_multiplier))) ++ return -EIO; + -+ 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; -+ } ++ return sprintf(buf, "%llu", led_brightness_multiplier); +} + - 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 ssize_t led_brightness_multiplier_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) +{ -+} -+ - 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); ++ struct led_classdev *cdev = dev_get_drvdata(dev); ++ struct steamdeck_led *sd = container_of(cdev, struct steamdeck_led, ++ cdev); ++ unsigned long value; + -+ /* 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; ++ if (kstrtoul(buf, 10, &value) || value > 100) ++ return -EINVAL; + - 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 ++ if (ACPI_FAILURE(acpi_execute_simple_method(sd->adev->handle, ++ "SLDM", value))) ++ return -EIO; + - 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)); ++ return count; +} + - 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; ++static DEVICE_ATTR_RW(led_brightness_multiplier); + -+ 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 struct attribute *steamdeck_led_attrs[] = { ++ &dev_attr_led_brightness_multiplier.attr, ++ NULL ++}; ++ATTRIBUTE_GROUPS(steamdeck_led); + - 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) + static int steamdeck_leds_brightness_set(struct led_classdev *cdev, + enum led_brightness value) { -+ 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; +@@ -44,6 +92,7 @@ static int steamdeck_leds_probe(struct platform_device *pdev) + sd->cdev.name = "status:white"; + sd->cdev.brightness_set_blocking = steamdeck_leds_brightness_set; + sd->cdev.max_brightness = 100; ++ sd->cdev.groups = steamdeck_led_groups; -- 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); + ret = devm_led_classdev_register(dev, &sd->cdev); 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 |