[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250929053145.3113394-4-yicongsrfy@163.com>
Date: Mon, 29 Sep 2025 13:31:45 +0800
From: yicongsrfy@....com
To: oneukum@...e.com,
andrew+netdev@...n.ch,
davem@...emloft.net,
edumazet@...gle.com,
kuba@...nel.org
Cc: marcan@...can.st,
pabeni@...hat.com,
linux-usb@...r.kernel.org,
netdev@...r.kernel.org,
yicong@...inos.cn
Subject: [PATCH v2 3/3] net: usb: ax88179_178a: add USB device driver for config selection
From: Yi Cong <yicong@...inos.cn>
A similar reason was raised in ec51fbd1b8a2
(r8152: add USB device driver for config selection):
Linux prioritizes probing non-vendor-specific configurations.
Referring to the implementation of this patch, cfgselect is also
used for ax88179 to override the default configuration selection.
Signed-off-by: Yi Cong <yicong@...inos.cn>
---
drivers/net/usb/ax88179_178a.c | 72 ++++++++++++++++++++++++++++++++--
1 file changed, 69 insertions(+), 3 deletions(-)
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index 29cbe9ddd610..965d2a66695d 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -14,6 +14,7 @@
#include <uapi/linux/mdio.h>
#include <linux/mdio.h>
+#define MODULENAME "ax88179_178a"
#define AX88179_PHY_ID 0x03
#define AX_EEPROM_LEN 0x100
#define AX88179_EEPROM_MAGIC 0x17900b95
@@ -1713,6 +1714,16 @@ static int ax88179_stop(struct usbnet *dev)
return 0;
}
+static int ax88179_probe(struct usb_interface *intf, const struct usb_device_id *i)
+{
+ if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) {
+ printk("[YCDBG][%s:%d] bInterfaceClass:%d\n", __func__, __LINE__, intf->cur_altsetting->desc.bInterfaceClass);
+ return -ENODEV;
+ }
+
+ return usbnet_probe(intf, i);
+}
+
static const struct driver_info ax88179_info = {
.description = "ASIX AX88179 USB 3.0 Gigabit Ethernet",
.bind = ax88179_bind,
@@ -1941,9 +1952,9 @@ static const struct usb_device_id products[] = {
MODULE_DEVICE_TABLE(usb, products);
static struct usb_driver ax88179_178a_driver = {
- .name = "ax88179_178a",
+ .name = MODULENAME,
.id_table = products,
- .probe = usbnet_probe,
+ .probe = ax88179_probe,
.suspend = ax88179_suspend,
.resume = ax88179_resume,
.reset_resume = ax88179_resume,
@@ -1952,7 +1963,62 @@ static struct usb_driver ax88179_178a_driver = {
.disable_hub_initiated_lpm = 1,
};
-module_usb_driver(ax88179_178a_driver);
+static int ax88179_cfgselector_probe(struct usb_device *udev)
+{
+ struct usb_host_config *c;
+ int i, num_configs;
+
+ /* The vendor mode is not always config #1, so to find it out. */
+ c = udev->config;
+ num_configs = udev->descriptor.bNumConfigurations;
+ for (i = 0; i < num_configs; (i++, c++)) {
+ struct usb_interface_descriptor *desc = NULL;
+
+ if (!c->desc.bNumInterfaces)
+ continue;
+ desc = &c->intf_cache[0]->altsetting->desc;
+ if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
+ break;
+ }
+
+ if (i == num_configs)
+ return -ENODEV;
+
+ if (usb_set_configuration(udev, c->desc.bConfigurationValue)) {
+ dev_err(&udev->dev, "Failed to set configuration %d\n",
+ c->desc.bConfigurationValue);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static struct usb_device_driver ax88179_cfgselector_driver = {
+ .name = MODULENAME "-cfgselector",
+ .probe = ax88179_cfgselector_probe,
+ .id_table = products,
+ .generic_subclass = 1,
+ .supports_autosuspend = 1,
+};
+
+static int __init ax88179_driver_init(void)
+{
+ int ret;
+
+ ret = usb_register_device_driver(&ax88179_cfgselector_driver, THIS_MODULE);
+ if (ret)
+ return ret;
+ return usb_register(&ax88179_178a_driver);
+}
+
+static void __exit ax88179_driver_exit(void)
+{
+ usb_deregister(&ax88179_178a_driver);
+ usb_deregister_device_driver(&ax88179_cfgselector_driver);
+}
+
+module_init(ax88179_driver_init);
+module_exit(ax88179_driver_exit);
MODULE_DESCRIPTION("ASIX AX88179/178A based USB 3.0/2.0 Gigabit Ethernet Devices");
MODULE_LICENSE("GPL");
--
2.25.1
Powered by blists - more mailing lists