* [PATCH AUTOSEL 5.10 2/5] HID: pidff: Do not send effect envelope if it's empty
2025-03-31 14:57 [PATCH AUTOSEL 5.10 1/5] HID: pidff: Convert infinite length from Linux API to PID standard Sasha Levin
@ 2025-03-31 14:57 ` Sasha Levin
2025-03-31 14:57 ` [PATCH AUTOSEL 5.10 3/5] HID: pidff: Fix null pointer dereference in pidff_find_fields Sasha Levin
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2025-03-31 14:57 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Tomasz Pakuła, Michał Kopeć,
Paul Dino Jones, Cristóferson Bueno, Pablo Cisneros,
Jiri Kosina, Sasha Levin, jikos, bentiss, linux-usb, linux-input
From: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
[ Upstream commit 8876fc1884f5b39550c8387ff3176396c988541d ]
Envelope struct is always initialized, but the envelope itself is
optional as described in USB PID Device class definition 1.0.
5.1.1.1 Type Specific Block Offsets
...
4) Effects that do not use Condition Blocks use 1 Parameter Block and
an *optional* Envelope Block.
Sending out "empty" envelope breaks force feedback on some devices with
games that use SINE effect + offset to emulate constant force effect, as
well as generally breaking Constant/Periodic effects. One of the affected
brands is Moza Racing.
This change prevents the envelope from being sent if it contains all
0 values while keeping the old behavior of only sending it, if it differs
from the old one.
Changes in v6:
- Simplify the checks to make them clearer
- Fix possible null pointer dereference while calling
pidff_needs_set_envelope
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Michał Kopeć <michal@nozomi.space>
Reviewed-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Cristóferson Bueno <cbueno81@gmail.com>
Tested-by: Pablo Cisneros <patchkez@protonmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/usbhid/hid-pidff.c | 42 +++++++++++++++++++---------------
1 file changed, 24 insertions(+), 18 deletions(-)
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index badcb5f28607e..ba0d7cb15377e 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -262,10 +262,22 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
static int pidff_needs_set_envelope(struct ff_envelope *envelope,
struct ff_envelope *old)
{
- return envelope->attack_level != old->attack_level ||
- envelope->fade_level != old->fade_level ||
+ bool needs_new_envelope;
+ needs_new_envelope = envelope->attack_level != 0 ||
+ envelope->fade_level != 0 ||
+ envelope->attack_length != 0 ||
+ envelope->fade_length != 0;
+
+ if (!needs_new_envelope)
+ return false;
+
+ if (!old)
+ return needs_new_envelope;
+
+ return envelope->attack_level != old->attack_level ||
+ envelope->fade_level != old->fade_level ||
envelope->attack_length != old->attack_length ||
- envelope->fade_length != old->fade_length;
+ envelope->fade_length != old->fade_length;
}
/*
@@ -580,11 +592,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
pidff_set_effect_report(pidff, effect);
if (!old || pidff_needs_set_constant(effect, old))
pidff_set_constant_force_report(pidff, effect);
- if (!old ||
- pidff_needs_set_envelope(&effect->u.constant.envelope,
- &old->u.constant.envelope))
- pidff_set_envelope_report(pidff,
- &effect->u.constant.envelope);
+ if (pidff_needs_set_envelope(&effect->u.constant.envelope,
+ old ? &old->u.constant.envelope : NULL))
+ pidff_set_envelope_report(pidff, &effect->u.constant.envelope);
break;
case FF_PERIODIC:
@@ -619,11 +629,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
pidff_set_effect_report(pidff, effect);
if (!old || pidff_needs_set_periodic(effect, old))
pidff_set_periodic_report(pidff, effect);
- if (!old ||
- pidff_needs_set_envelope(&effect->u.periodic.envelope,
- &old->u.periodic.envelope))
- pidff_set_envelope_report(pidff,
- &effect->u.periodic.envelope);
+ if (pidff_needs_set_envelope(&effect->u.periodic.envelope,
+ old ? &old->u.periodic.envelope : NULL))
+ pidff_set_envelope_report(pidff, &effect->u.periodic.envelope);
break;
case FF_RAMP:
@@ -637,11 +645,9 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
pidff_set_effect_report(pidff, effect);
if (!old || pidff_needs_set_ramp(effect, old))
pidff_set_ramp_force_report(pidff, effect);
- if (!old ||
- pidff_needs_set_envelope(&effect->u.ramp.envelope,
- &old->u.ramp.envelope))
- pidff_set_envelope_report(pidff,
- &effect->u.ramp.envelope);
+ if (pidff_needs_set_envelope(&effect->u.ramp.envelope,
+ old ? &old->u.ramp.envelope : NULL))
+ pidff_set_envelope_report(pidff, &effect->u.ramp.envelope);
break;
case FF_SPRING:
--
2.39.5
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH AUTOSEL 5.10 3/5] HID: pidff: Fix null pointer dereference in pidff_find_fields
2025-03-31 14:57 [PATCH AUTOSEL 5.10 1/5] HID: pidff: Convert infinite length from Linux API to PID standard Sasha Levin
2025-03-31 14:57 ` [PATCH AUTOSEL 5.10 2/5] HID: pidff: Do not send effect envelope if it's empty Sasha Levin
@ 2025-03-31 14:57 ` Sasha Levin
2025-04-18 16:57 ` Pavel Machek
2025-03-31 14:57 ` [PATCH AUTOSEL 5.10 4/5] ALSA: hda: intel: Fix Optimus when GPU has no sound Sasha Levin
2025-03-31 14:57 ` [PATCH AUTOSEL 5.10 5/5] ALSA: usb-audio: Fix CME quirk for UF series keyboards Sasha Levin
3 siblings, 1 reply; 6+ messages in thread
From: Sasha Levin @ 2025-03-31 14:57 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Tomasz Pakuła, Nolan Nicholson, Tomasz Pakuła,
Michał Kopeć,
Paul Dino Jones, Cristóferson Bueno, Pablo Cisneros,
Jiri Kosina, Sasha Levin, jikos, bentiss, linux-usb, linux-input
From: Tomasz Pakuła <forest10pl@gmail.com>
[ Upstream commit 22a05462c3d0eee15154faf8d13c49e6295270a5 ]
This function triggered a null pointer dereference if used to search for
a report that isn't implemented on the device. This happened both for
optional and required reports alike.
The same logic was applied to pidff_find_special_field and although
pidff_init_fields should return an error earlier if one of the required
reports is missing, future modifications could change this logic and
resurface this possible null pointer dereference again.
LKML bug report:
https://lore.kernel.org/all/CAL-gK7f5=R0nrrQdPtaZZr1fd-cdAMbDMuZ_NLA8vM0SX+nGSw@mail.gmail.com
Reported-by: Nolan Nicholson <nolananicholson@gmail.com>
Signed-off-by: Tomasz Pakuła <tomasz.pakula.oficjalny@gmail.com>
Reviewed-by: Michał Kopeć <michal@nozomi.space>
Reviewed-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Paul Dino Jones <paul@spacefreak18.xyz>
Tested-by: Cristóferson Bueno <cbueno81@gmail.com>
Tested-by: Pablo Cisneros <patchkez@protonmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/hid/usbhid/hid-pidff.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index ba0d7cb15377e..7801294fe086d 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -770,6 +770,11 @@ static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude)
static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
struct hid_report *report, int count, int strict)
{
+ if (!report) {
+ pr_debug("pidff_find_fields, null report\n");
+ return -1;
+ }
+
int i, j, k, found;
for (k = 0; k < count; k++) {
@@ -883,6 +888,11 @@ static int pidff_reports_ok(struct pidff_device *pidff)
static struct hid_field *pidff_find_special_field(struct hid_report *report,
int usage, int enforce_min)
{
+ if (!report) {
+ pr_debug("pidff_find_special_field, null report\n");
+ return NULL;
+ }
+
int i;
for (i = 0; i < report->maxfield; i++) {
--
2.39.5
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH AUTOSEL 5.10 3/5] HID: pidff: Fix null pointer dereference in pidff_find_fields
2025-03-31 14:57 ` [PATCH AUTOSEL 5.10 3/5] HID: pidff: Fix null pointer dereference in pidff_find_fields Sasha Levin
@ 2025-04-18 16:57 ` Pavel Machek
0 siblings, 0 replies; 6+ messages in thread
From: Pavel Machek @ 2025-04-18 16:57 UTC (permalink / raw)
To: Sasha Levin
Cc: linux-kernel, stable, Tomasz Pakuła, Nolan Nicholson,
Tomasz Pakuła, Michał Kopeć,
Paul Dino Jones, Cristóferson Bueno, Pablo Cisneros,
Jiri Kosina, jikos, bentiss, linux-usb, linux-input
[-- Attachment #1: Type: text/plain, Size: 1386 bytes --]
Hi!
> From: Tomasz Pakuła <forest10pl@gmail.com>
>
> [ Upstream commit 22a05462c3d0eee15154faf8d13c49e6295270a5 ]
>
> This function triggered a null pointer dereference if used to search for
> a report that isn't implemented on the device. This happened both for
> optional and required reports alike.
Ok.
> +++ b/drivers/hid/usbhid/hid-pidff.c
> @@ -770,6 +770,11 @@ static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude)
> static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
> struct hid_report *report, int count, int strict)
> {
> + if (!report) {
> + pr_debug("pidff_find_fields, null report\n");
> + return -1;
> + }
> +
> int i, j, k, found;
>
> for (k = 0; k < count; k++) {
> @@ -883,6 +888,11 @@ static int pidff_reports_ok(struct pidff_device *pidff)
> static struct hid_field *pidff_find_special_field(struct hid_report *report,
> int usage, int enforce_min)
> {
> + if (!report) {
> + pr_debug("pidff_find_special_field, null report\n");
> + return NULL;
> + }
> +
> int i;
But this is quite strange. Normally declarations go first. Not sure if
old compilers can handle this?
Best regards,
Pavel
--
DENX Software Engineering GmbH, Managing Director: Erika Unter
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH AUTOSEL 5.10 4/5] ALSA: hda: intel: Fix Optimus when GPU has no sound
2025-03-31 14:57 [PATCH AUTOSEL 5.10 1/5] HID: pidff: Convert infinite length from Linux API to PID standard Sasha Levin
2025-03-31 14:57 ` [PATCH AUTOSEL 5.10 2/5] HID: pidff: Do not send effect envelope if it's empty Sasha Levin
2025-03-31 14:57 ` [PATCH AUTOSEL 5.10 3/5] HID: pidff: Fix null pointer dereference in pidff_find_fields Sasha Levin
@ 2025-03-31 14:57 ` Sasha Levin
2025-03-31 14:57 ` [PATCH AUTOSEL 5.10 5/5] ALSA: usb-audio: Fix CME quirk for UF series keyboards Sasha Levin
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2025-03-31 14:57 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Maxim Mikityanskiy, Takashi Iwai, Sasha Levin, perex, tiwai,
yung-chuan.liao, peter.ujfalusi, pierre-louis.bossart,
hkallweit1, linux-sound
From: Maxim Mikityanskiy <maxtram95@gmail.com>
[ Upstream commit 2b360ba9a4936486380bc30d1eabceb40a714d98 ]
quirk_nvidia_hda() forcefully enables HDA controller on all NVIDIA GPUs,
because some buggy BIOSes leave it disabled. However, some dual-GPU
laptops do not have a functional HDA controller in DGPU, and BIOS
disables it on purpose. After quirk_nvidia_hda() reenables this dummy
HDA controller, attempting to probe it fails at azx_first_init(), which
is too late to cancel the probe, as it happens in azx_probe_continue().
The sna_hda_intel driver calls azx_free() and stops the chip, however,
it stays probed, and from the runtime PM point of view, the device
remains active (it was set as active by the PCI subsystem on probe). It
prevents vga_switcheroo from turning off the DGPU, because
pci_create_device_link() syncs power management for video and audio
devices.
Affected devices should be added to driver_denylist to prevent them from
probing early. This patch helps identify such devices by printing a
warning, and also forces the device to the suspended state to allow
vga_switcheroo turn off DGPU.
Signed-off-by: Maxim Mikityanskiy <maxtram95@gmail.com>
Link: https://patch.msgid.link/20250208214602.39607-2-maxtram95@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/pci/hda/hda_intel.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index fad3e8853be02..407bbf9264ac4 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1399,8 +1399,21 @@ static void azx_free(struct azx *chip)
if (use_vga_switcheroo(hda)) {
if (chip->disabled && hda->probe_continued)
snd_hda_unlock_devices(&chip->bus);
- if (hda->vga_switcheroo_registered)
+ if (hda->vga_switcheroo_registered) {
vga_switcheroo_unregister_client(chip->pci);
+
+ /* Some GPUs don't have sound, and azx_first_init fails,
+ * leaving the device probed but non-functional. As long
+ * as it's probed, the PCI subsystem keeps its runtime
+ * PM status as active. Force it to suspended (as we
+ * actually stop the chip) to allow GPU to suspend via
+ * vga_switcheroo, and print a warning.
+ */
+ dev_warn(&pci->dev, "GPU sound probed, but not operational: please add a quirk to driver_denylist\n");
+ pm_runtime_disable(&pci->dev);
+ pm_runtime_set_suspended(&pci->dev);
+ pm_runtime_enable(&pci->dev);
+ }
}
if (bus->chip_init) {
--
2.39.5
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH AUTOSEL 5.10 5/5] ALSA: usb-audio: Fix CME quirk for UF series keyboards
2025-03-31 14:57 [PATCH AUTOSEL 5.10 1/5] HID: pidff: Convert infinite length from Linux API to PID standard Sasha Levin
` (2 preceding siblings ...)
2025-03-31 14:57 ` [PATCH AUTOSEL 5.10 4/5] ALSA: hda: intel: Fix Optimus when GPU has no sound Sasha Levin
@ 2025-03-31 14:57 ` Sasha Levin
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2025-03-31 14:57 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Ricard Wanderlof, Takashi Iwai, Sasha Levin, clemens, perex,
tiwai, linux-sound
From: Ricard Wanderlof <ricard2013@butoba.net>
[ Upstream commit c2820405ba55a38932aa2177f026b70064296663 ]
Fix quirk for CME master keyboards so it not only handles
sysex but also song position pointer, MIDI timing clock, start
and stop messages, and active sensing. All of these can be
output by the CME UF series master keyboards.
Tested with a CME UF6 in a desktop Linux environment as
well as on the Zynthian Raspberry Pi based platform.
Signed-off-by: Ricard Wanderlof <ricard2013@butoba.net>
Link: https://patch.msgid.link/20250313-cme-fix-v1-1-d404889e4de8@butoba.net
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/usb/midi.c | 80 ++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 74 insertions(+), 6 deletions(-)
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index f0a70e912bddc..b09b7b3c0110e 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -505,16 +505,84 @@ static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep,
/*
* CME protocol: like the standard protocol, but SysEx commands are sent as a
- * single USB packet preceded by a 0x0F byte.
+ * single USB packet preceded by a 0x0F byte, as are system realtime
+ * messages and MIDI Active Sensing.
+ * Also, multiple messages can be sent in the same packet.
*/
static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep,
uint8_t *buffer, int buffer_length)
{
- if (buffer_length < 2 || (buffer[0] & 0x0f) != 0x0f)
- snd_usbmidi_standard_input(ep, buffer, buffer_length);
- else
- snd_usbmidi_input_data(ep, buffer[0] >> 4,
- &buffer[1], buffer_length - 1);
+ int remaining = buffer_length;
+
+ /*
+ * CME send sysex, song position pointer, system realtime
+ * and active sensing using CIN 0x0f, which in the standard
+ * is only intended for single byte unparsed data.
+ * So we need to interpret these here before sending them on.
+ * By default, we assume single byte data, which is true
+ * for system realtime (midi clock, start, stop and continue)
+ * and active sensing, and handle the other (known) cases
+ * separately.
+ * In contrast to the standard, CME does not split sysex
+ * into multiple 4-byte packets, but lumps everything together
+ * into one. In addition, CME can string multiple messages
+ * together in the same packet; pressing the Record button
+ * on an UF6 sends a sysex message directly followed
+ * by a song position pointer in the same packet.
+ * For it to have any reasonable meaning, a sysex message
+ * needs to be at least 3 bytes in length (0xf0, id, 0xf7),
+ * corresponding to a packet size of 4 bytes, and the ones sent
+ * by CME devices are 6 or 7 bytes, making the packet fragments
+ * 7 or 8 bytes long (six or seven bytes plus preceding CN+CIN byte).
+ * For the other types, the packet size is always 4 bytes,
+ * as per the standard, with the data size being 3 for SPP
+ * and 1 for the others.
+ * Thus all packet fragments are at least 4 bytes long, so we can
+ * skip anything that is shorter; this also conveniantly skips
+ * packets with size 0, which CME devices continuously send when
+ * they have nothing better to do.
+ * Another quirk is that sometimes multiple messages are sent
+ * in the same packet. This has been observed for midi clock
+ * and active sensing i.e. 0x0f 0xf8 0x00 0x00 0x0f 0xfe 0x00 0x00,
+ * but also multiple note ons/offs, and control change together
+ * with MIDI clock. Similarly, some sysex messages are followed by
+ * the song position pointer in the same packet, and occasionally
+ * additionally by a midi clock or active sensing.
+ * We handle this by looping over all data and parsing it along the way.
+ */
+ while (remaining >= 4) {
+ int source_length = 4; /* default */
+
+ if ((buffer[0] & 0x0f) == 0x0f) {
+ int data_length = 1; /* default */
+
+ if (buffer[1] == 0xf0) {
+ /* Sysex: Find EOX and send on whole message. */
+ /* To kick off the search, skip the first
+ * two bytes (CN+CIN and SYSEX (0xf0).
+ */
+ uint8_t *tmp_buf = buffer + 2;
+ int tmp_length = remaining - 2;
+
+ while (tmp_length > 1 && *tmp_buf != 0xf7) {
+ tmp_buf++;
+ tmp_length--;
+ }
+ data_length = tmp_buf - buffer;
+ source_length = data_length + 1;
+ } else if (buffer[1] == 0xf2) {
+ /* Three byte song position pointer */
+ data_length = 3;
+ }
+ snd_usbmidi_input_data(ep, buffer[0] >> 4,
+ &buffer[1], data_length);
+ } else {
+ /* normal channel events */
+ snd_usbmidi_standard_input(ep, buffer, source_length);
+ }
+ buffer += source_length;
+ remaining -= source_length;
+ }
}
/*
--
2.39.5
^ permalink raw reply [flat|nested] 6+ messages in thread