Message ID | 20250410024626.981215-1-ivan.hu@canonical.com |
---|---|
State | New |
Headers | show |
Series | usb: quirks: Add quirk to prefer vendor-specific configuration | expand |
On Thu, Apr 10, 2025 at 10:46:26AM +0800, Ivan Hu wrote: > Some USB devices with multiple configurations expose a vendor-specific > interface class that should be preferred by default. However, the generic > usb_choose_configuration() logic selects the first configuration whose > first interface uses a non-vendor-specific class, which can lead to > incomplete or limited functionality. > > Introduce a new quirk, USB_QUIRK_CHOOSE_VENDOR_SPEC_CFG, which > instructs the USB core to prefer a configuration that contains a > vendor-specific interface class when multiple configurations are present. > > Apply this quirk to the ASIX AX88179 USB Ethernet adapter > (0x0b95:0x1790), which requires selecting its vendor-specific > configuration for full functionality, instead of falling back to > cdc_ncm. Shouldn't this be done in userspace instead? And how does other operating systems handle this, the "first" configuration is usually the default for them as well, do they have some built-in quirk to handle this or do they rely on a vendor-provided driver? thanks, greg k-h
On 2025/4/10 14:58, Greg KH wrote: > On Thu, Apr 10, 2025 at 10:46:26AM +0800, Ivan Hu wrote: >> Some USB devices with multiple configurations expose a vendor-specific >> interface class that should be preferred by default. However, the generic >> usb_choose_configuration() logic selects the first configuration whose >> first interface uses a non-vendor-specific class, which can lead to >> incomplete or limited functionality. >> >> Introduce a new quirk, USB_QUIRK_CHOOSE_VENDOR_SPEC_CFG, which >> instructs the USB core to prefer a configuration that contains a >> vendor-specific interface class when multiple configurations are present. >> >> Apply this quirk to the ASIX AX88179 USB Ethernet adapter >> (0x0b95:0x1790), which requires selecting its vendor-specific >> configuration for full functionality, instead of falling back to >> cdc_ncm. > > Shouldn't this be done in userspace instead? And how does other > operating systems handle this, the "first" configuration is usually the > default for them as well, do they have some built-in quirk to handle > this or do they rely on a vendor-provided driver? > > thanks, > > greg k-h > Hi Greg, Thanks for the feedback. In this case, the device advertises three configuration descriptors. The first is vendor-specific, the second is CDC-NCM, and the third is CDC-Ether: Device Descriptor: idVendor 0x0b95 ASIX Electronics Corp. idProduct 0x1790 AX88179 Gigabit Ethernet bNumConfigurations 3 Configuration 1: Interface 0: bInterfaceClass 255 Vendor Specific Class Configuration 2: Interface 0: bInterfaceClass 2 Communications bInterfaceSubClass 13 (CDC-NCM) Configuration 3: Interface 0: bInterfaceClass 2 Communications bInterfaceSubClass 6 (CDC-Ether) In drivers/usb/core/generic.c, the logic currently prefers the first configuration whose first interface is non-vendor-specific, based on the assumption that Linux is more likely to have a generic class driver than a vendor-specific one: /* From the remaining configs, choose the first one whose * first interface is for a non-vendor-specific class. * Reason: Linux is more likely to have a class driver * than a vendor-specific driver. */ This results in the CDC-NCM configuration being selected by default, even though the kernel already supports the vendor-specific driver ax88179_178a, which provides the correct and full functionality. Of course, this could be handled in userspace, but due to security restrictions on certain systems, such as Ubuntu Core, modifying configuration selection in userspace becomes significantly more complex and less straightforward. And although I don’t have insight into the exact design in Windows, but during testing on a standard Windows install, the device is correctly initialized with the vendor driver without any additional configuration or modification. Given that this quirk is device-specific and not a general change in policy, the proposed quirk simply allows the kernel to prefer the correct vendor-specific configuration when it's known to be required. Cheers, Ivan
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 9c6ae5e1198b..19bf35ede5a0 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -23,6 +23,7 @@ #include <linux/usb/hcd.h> #include <linux/string_choices.h> #include <uapi/linux/usb/audio.h> +#include <linux/usb/quirks.h> #include "usb.h" static int is_rndis(struct usb_interface_descriptor *desc) @@ -155,6 +156,20 @@ int usb_choose_configuration(struct usb_device *udev) continue; } + /* This quirk forces the selection of a vendor-specific + * interface class configuration when multiple configurations + * are present. + */ + if (num_configs > 1 && + udev->descriptor.bDeviceClass == + USB_CLASS_PER_INTERFACE && + udev->quirks & USB_QUIRK_CHOOSE_VENDOR_SPEC_CFG + && (desc && desc->bInterfaceClass == + USB_CLASS_VENDOR_SPEC)) { + best = c; + break; + } + /* When the first config's first interface is one of Microsoft's * pet nonstandard Ethernet-over-USB protocols, ignore it unless * this kernel has enabled the necessary host side driver. diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 8efbacc5bc34..1e0e05cb29df 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -565,6 +565,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, + /* ASIX AS88179 */ + { USB_DEVICE(0x0b95, 0x1790), .driver_info = USB_QUIRK_CHOOSE_VENDOR_SPEC_CFG }, + { } /* terminating entry must be last */ }; diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 59409c1fc3de..1f73bfc191f0 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -75,4 +75,7 @@ /* short SET_ADDRESS request timeout */ #define USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT BIT(16) +/* force selection of vendor-specific configuration*/ +#define USB_QUIRK_CHOOSE_VENDOR_SPEC_CFG BIT(17) + #endif /* __LINUX_USB_QUIRKS_H */
Some USB devices with multiple configurations expose a vendor-specific interface class that should be preferred by default. However, the generic usb_choose_configuration() logic selects the first configuration whose first interface uses a non-vendor-specific class, which can lead to incomplete or limited functionality. Introduce a new quirk, USB_QUIRK_CHOOSE_VENDOR_SPEC_CFG, which instructs the USB core to prefer a configuration that contains a vendor-specific interface class when multiple configurations are present. Apply this quirk to the ASIX AX88179 USB Ethernet adapter (0x0b95:0x1790), which requires selecting its vendor-specific configuration for full functionality, instead of falling back to cdc_ncm. Signed-off-by: Ivan Hu <ivan.hu@canonical.com> --- drivers/usb/core/generic.c | 15 +++++++++++++++ drivers/usb/core/quirks.c | 3 +++ include/linux/usb/quirks.h | 3 +++ 3 files changed, 21 insertions(+)