Re: [PATCH v9 2/5] HID: wacom: Advertise SW_MUTE_DEVICE capability prior to registration
From: Ping Cheng
Date: Tue Sep 08 2026 - 18:21:28 EST
I tested the devices that I can reach, mainly the ones released in the
past 10 years or so. The tablets all worked. No crashes whatsoever. I
am comfortable to give the whole set of this version an acked-by and a
tested-by to help it move forward.
Acked-by: Ping Cheng <ping.cheng@xxxxxxxxx>
Tested-by: Ping Cheng <ping.cheng@xxxxxxxxx>
With that said, the SW_MUTE_DEVICE capability assigned through a
softkey is not properly recognized. I've figured out the root cause. I
will submit a patch after this set is merged. The main value of this
set is to resolve the Use-After-Free issue and the redesign of the
shared sibling data lifecycle. The individual softkey feature can be
addressed separately.
Hope my testing results make the maintainers feel comfortable too.
Thank you,
Ping
On Wed, Sep 2, 2026 at 8:20 AM Lee Jones <lee@xxxxxxxxxx> wrote:
>
> Input subsystem guidelines require that device capabilities are advertised
> before the input device is registered. The Wacom driver was violating
> this by advertising the SW_MUTE_DEVICE capability post-registration in
> wacom_set_shared_values() (and duplicating it in device-specific setup
> cases).
>
> Resolve this by moving the SW_MUTE_DEVICE capability setup to
> wacom_setup_touch_input_capabilities() for all touch devices that support
> it.
>
> For generic touch devices whose capabilities depend on mute switch
> usages parsed from a sibling Pen/Pad interface, defer registration
> with -EPROBE_DEFER until the sibling has parsed its descriptors and
> initialized shared capabilities.
>
> Cc: stable@xxxxxxxxxxxxxxx
> Fixes: d2ec58aee8b1 ("HID: wacom: generic: support generic touch switch")
> Signed-off-by: Lee Jones <lee@xxxxxxxxxx>
> ---
>
> v4 -> v5: New patch used to split out SW_MUTE_DEVICE as per Jason's request
> v5 -> v6: Unconditionally advertise SW_MUTE_DEVICE on generic touch devices
> v6 -> v7: Only advertise SW_MUTE_DEVICE on composite USB generic touch devices
> v7 -> v8: Replace heuristic with probe deferral until sibling Pen/Pad is parsed
> Split out 'hdev->product' cleanups into a separate standalone patch
> v8 -> v9: Fix TOCTOU race by assigning shared sibling pointers in wacom_set_shared_values()
> Support Pad interfaces in sibling deferral logic
>
> drivers/hid/wacom_sys.c | 68 ++++++++++++++++++++++++++++++-----------
> drivers/hid/wacom_wac.c | 4 +++
> 2 files changed, 55 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
> index 0eafa483b7f7..026a6be467d3 100644
> --- a/drivers/hid/wacom_sys.c
> +++ b/drivers/hid/wacom_sys.c
> @@ -912,14 +912,6 @@ static int wacom_add_shared_data(struct hid_device *hdev)
> wacom_wac->shared = &data->shared;
>
> retval = devm_add_action_or_reset(&hdev->dev, wacom_remove_shared_data, wacom);
> - if (retval)
> - return retval;
> -
> - if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)
> - wacom_wac->shared->touch = hdev;
> - else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN)
> - wacom_wac->shared->pen = hdev;
> -
> return retval;
> }
>
> @@ -2343,10 +2335,7 @@ static void wacom_release_resources(struct wacom *wacom)
>
> static void wacom_set_shared_values(struct wacom_wac *wacom_wac)
> {
> - if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) {
> - wacom_wac->shared->type = wacom_wac->features.type;
> - wacom_wac->shared->touch_input = wacom_wac->touch_input;
> - }
> + struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac);
>
> if (wacom_wac->has_mute_touch_switch) {
> wacom_wac->shared->has_mute_touch_switch = true;
> @@ -2359,14 +2348,54 @@ static void wacom_set_shared_values(struct wacom_wac *wacom_wac)
> wacom_wac->shared->is_touch_on = true;
> }
>
> - if (wacom_wac->shared->has_mute_touch_switch &&
> - wacom_wac->shared->touch_input) {
> - set_bit(EV_SW, wacom_wac->shared->touch_input->evbit);
> - input_set_capability(wacom_wac->shared->touch_input, EV_SW,
> - SW_MUTE_DEVICE);
> + if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) {
> + wacom_wac->shared->type = wacom_wac->features.type;
> + wacom_wac->shared->touch_input = wacom_wac->touch_input;
> + wacom_wac->shared->touch = wacom->hdev;
> + } else if (wacom_wac->features.device_type &
> + (WACOM_DEVICETYPE_PEN | WACOM_DEVICETYPE_PAD)) {
> + wacom_wac->shared->pen = wacom->hdev;
> }
> }
>
> +static bool wacom_sibling_pending(struct wacom *wacom)
> +{
> + struct hid_device *hdev = wacom->hdev;
> + const struct wacom_features *features = &wacom->wacom_wac.features;
> + struct usb_host_config *actconfig;
> + int i;
> +
> + if (features->type != HID_GENERIC ||
> + !(features->device_type & WACOM_DEVICETYPE_TOUCH))
> + return false;
> +
> + if (wacom->wacom_wac.shared &&
> + rcu_access_pointer(wacom->wacom_wac.shared->pen))
> + return false;
> +
> + if (!hid_is_usb(hdev) || !wacom->usbdev)
> + return false;
> +
> + if (features->oPid != HID_ANY_ID && features->oPid != 0)
> + return true;
> +
> + actconfig = wacom->usbdev->actconfig;
> + if (actconfig && actconfig->desc.bNumInterfaces > 1) {
> + for (i = 0; i < actconfig->desc.bNumInterfaces; i++) {
> + struct usb_interface *sibling_intf = actconfig->interface[i];
> +
> + if (!sibling_intf || sibling_intf == wacom->intf)
> + continue;
> +
> + if (sibling_intf->cur_altsetting->desc.bInterfaceClass ==
> + USB_INTERFACE_CLASS_HID)
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
> {
> struct wacom_wac *wacom_wac = &wacom->wacom_wac;
> @@ -2444,6 +2473,11 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
> if (error)
> goto fail;
>
> + if (wacom_sibling_pending(wacom)) {
> + error = -EPROBE_DEFER;
> + goto fail;
> + }
> +
> error = wacom_setup_inputs(wacom);
> if (error)
> goto fail;
> diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
> index 4436faf2d2bb..a7e3817aa2c4 100644
> --- a/drivers/hid/wacom_wac.c
> +++ b/drivers/hid/wacom_wac.c
> @@ -3965,6 +3965,10 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
>
> if (features->type == HID_GENERIC) {
> hid_dbg(hdev, "generic touch setup\n");
> + if (wacom_wac->shared && wacom_wac->shared->has_mute_touch_switch) {
> + input_set_capability(input_dev, EV_SW, SW_MUTE_DEVICE);
> + wacom_wac->has_mute_touch_switch = true;
> + }
> /* setup has already been done */
> return 0;
> }
> --
> 2.55.0.966.g6673acef38-goog
>
>