]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ALSA: usb-audio: Refine string-descriptor-based quirk matching
authorRong Zhang <i@rong.moe>
Thu, 5 Mar 2026 17:46:39 +0000 (01:46 +0800)
committerTakashi Iwai <tiwai@suse.de>
Thu, 5 Mar 2026 19:49:10 +0000 (20:49 +0100)
Remove snd_usb_get_string() and use the manufacturer and product strings
stored in struct usb_device directly to match quirk table entries. Their
NULLity can be checked to determine if the device has no these strings.
This simplifies the code a lot.

Meanwhile, allow quirk table entries to match "no string" explicitly, and
add appropriate comments to show the expected usages of
DEVICE_STRING_FLG() and VENDOR_STRING_FLG(). These changes are tiny and
doesn't form another separate patch, so that back-and-forth changes can
be avoided.

Suggested-by: Terry Junge <linuxsound@cosmicgizmosystems.com>
Link: https://lore.kernel.org/r/b59da54a-9c80-4212-a337-c5ea98da52d1@cosmicgizmosystems.com
Signed-off-by: Rong Zhang <i@rong.moe>
Link: https://patch.msgid.link/20260305174711.1106324-1-i@rong.moe
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/usb/quirks.c

index 17f6be4d2350ef5ecd2047baf768b3d637627570..ab67f7826e9b572e74c587aced964e3ebbfff79b 100644 (file)
@@ -2153,7 +2153,28 @@ struct usb_audio_quirk_flags_table {
        { .id = USB_ID(vid, pid), .flags = (_flags) }
 #define VENDOR_FLG(vid, _flags) DEVICE_FLG(vid, 0, _flags)
 
-/* Use as a last resort if using DEVICE_FLG() is prone to VID/PID conflicts. */
+/*
+ * Use as a last resort if using DEVICE_FLG() is prone to VID/PID conflicts.
+ *
+ * Usage:
+ *   // match vid, pid, "manufacturer", and "product"
+ *   DEVICE_STRING_FLG(vid, pid, "manufacturer", "product", flags)
+ *
+ *   // match vid, pid, "manufacturer", and any product string
+ *   DEVICE_STRING_FLG(vid, pid, "manufacturer", NULL,      flags)
+ *
+ *   // match vid, pid, "manufacturer", and device must have no product string
+ *   DEVICE_STRING_FLG(vid, pid, "manufacturer", "",        flags)
+ *
+ *   // match vid, pid, any manufacturer string, and "product"
+ *   DEVICE_STRING_FLG(vid, pid, NULL,           "product", flags)
+ *
+ *   // match vid, pid, no manufacturer string, and "product"
+ *   DEVICE_STRING_FLG(vid, pid, "",             "product", flags)
+ *
+ *   // match vid, pid, no manufacturer string, and no product string
+ *   DEVICE_STRING_FLG(vid, pid, "",             "",        flags)
+ */
 #define DEVICE_STRING_FLG(vid, pid, _manufacturer, _product, _flags)   \
 {                                                                      \
        .id = USB_ID(vid, pid),                                         \
@@ -2164,7 +2185,16 @@ struct usb_audio_quirk_flags_table {
        .flags = (_flags),                                              \
 }
 
-/* Use as a last resort if using VENDOR_FLG() is prone to VID conflicts. */
+/*
+ * Use as a last resort if using VENDOR_FLG() is prone to VID conflicts.
+ *
+ * Usage:
+ *   // match vid, and "manufacturer"
+ *   VENDOR_STRING_FLG(vid, "manufacturer", flags)
+ *
+ *   // match vid, and device must have no manufacturer string
+ *   VENDOR_STRING_FLG(vid, "",             flags)
+ */
 #define VENDOR_STRING_FLG(vid, _manufacturer, _flags)                  \
        DEVICE_STRING_FLG(vid, 0, _manufacturer, NULL, _flags)
 
@@ -2595,63 +2625,23 @@ void snd_usb_apply_flag_dbg(const char *reason,
        }
 }
 
-#define USB_STRING_SIZE 128
-
-static char *snd_usb_get_string(struct snd_usb_audio *chip, int id)
-{
-       char *buf;
-       int ret;
-
-       /*
-        * Devices without the corresponding string descriptor.
-        * This is non-fatal as *_STRING_FLG have nothing to do in this case.
-        */
-       if (id == 0)
-               return ERR_PTR(-ENODATA);
-
-       buf = kmalloc(USB_STRING_SIZE, GFP_KERNEL);
-       if (buf == NULL)
-               return ERR_PTR(-ENOMEM);
-
-       ret = usb_string(chip->dev, id, buf, USB_STRING_SIZE);
-       if (ret < 0) {
-               usb_audio_warn(chip, "failed to get string for id%d: %d\n", id, ret);
-               kfree(buf);
-               return ERR_PTR(ret);
-       }
-
-       return buf;
-}
-
 void snd_usb_init_quirk_flags_table(struct snd_usb_audio *chip)
 {
        const struct usb_audio_quirk_flags_table *p;
-       char *manufacturer __free(kfree) = NULL;
-       char *product __free(kfree) = NULL;
 
        for (p = quirk_flags_table; p->id; p++) {
                if (chip->usb_id == p->id ||
                    (!USB_ID_PRODUCT(p->id) &&
                     USB_ID_VENDOR(chip->usb_id) == USB_ID_VENDOR(p->id))) {
                        /* Handle DEVICE_STRING_FLG/VENDOR_STRING_FLG. */
-                       if (p->usb_string_match && p->usb_string_match->manufacturer) {
-                               if (!manufacturer) {
-                                       manufacturer = snd_usb_get_string(chip,
-                                               chip->dev->descriptor.iManufacturer);
-                               }
-                               if (IS_ERR_OR_NULL(manufacturer) ||
-                                   strcmp(p->usb_string_match->manufacturer, manufacturer))
-                                       continue;
-                       }
-                       if (p->usb_string_match && p->usb_string_match->product) {
-                               if (!product) {
-                                       product = snd_usb_get_string(chip,
-                                               chip->dev->descriptor.iProduct);
-                               }
-                               if (IS_ERR_OR_NULL(product) ||
-                                   strcmp(p->usb_string_match->product, product))
-                                       continue;
-                       }
+                       if (p->usb_string_match && p->usb_string_match->manufacturer &&
+                           strcmp(p->usb_string_match->manufacturer,
+                                  chip->dev->manufacturer ? chip->dev->manufacturer : ""))
+                               continue;
+                       if (p->usb_string_match && p->usb_string_match->product &&
+                           strcmp(p->usb_string_match->product,
+                                  chip->dev->product ? chip->dev->product : ""))
+                               continue;
 
                        snd_usb_apply_flag_dbg("builtin table", chip, p->flags);
                        chip->quirk_flags |= p->flags;