795-v6.3-01-r8152-add-USB-device-driver-for-config-selection.patch 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. From ec51fbd1b8a2bca2948dede99c14ec63dc57ff6b Mon Sep 17 00:00:00 2001
  2. From: Bjørn Mork <[email protected]>
  3. Date: Fri, 6 Jan 2023 17:07:38 +0100
  4. Subject: [PATCH] r8152: add USB device driver for config selection
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. Subclassing the generic USB device driver to override the
  9. default configuration selection regardless of matching interface
  10. drivers.
  11. The r815x family devices expose a vendor specific function which
  12. the r8152 interface driver wants to handle. This is the preferred
  13. device mode. Additionally one or more USB class functions are
  14. usually supported for hosts lacking a vendor specific driver. The
  15. choice is USB configuration based, with one alternate function per
  16. configuration.
  17. Example device with both NCM and ECM alternate cfgs:
  18. T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 4 Spd=5000 MxCh= 0
  19. D: Ver= 3.20 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 9 #Cfgs= 3
  20. P: Vendor=0bda ProdID=8156 Rev=31.00
  21. S: Manufacturer=Realtek
  22. S: Product=USB 10/100/1G/2.5G LAN
  23. S: SerialNumber=001000001
  24. C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=256mA
  25. I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=00 Driver=r8152
  26. E: Ad=81(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms
  27. E: Ad=02(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms
  28. E: Ad=83(I) Atr=03(Int.) MxPS= 2 Ivl=128ms
  29. C: #Ifs= 2 Cfg#= 2 Atr=a0 MxPwr=256mA
  30. I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=0d Prot=00 Driver=
  31. E: Ad=83(I) Atr=03(Int.) MxPS= 16 Ivl=128ms
  32. I: If#= 1 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=01 Driver=
  33. I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=01 Driver=
  34. E: Ad=81(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms
  35. E: Ad=02(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms
  36. C: #Ifs= 2 Cfg#= 3 Atr=a0 MxPwr=256mA
  37. I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=06 Prot=00 Driver=
  38. E: Ad=83(I) Atr=03(Int.) MxPS= 16 Ivl=128ms
  39. I: If#= 1 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=00 Driver=
  40. I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=
  41. E: Ad=81(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms
  42. E: Ad=02(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms
  43. A problem with this is that Linux will prefer class functions over
  44. vendor specific functions. Using the above example, Linux defaults
  45. to cfg #2, running the device in a sub-optimal NCM mode.
  46. Previously we've attempted to work around the problem by
  47. blacklisting the devices in the ECM class driver "cdc_ether", and
  48. matching on the ECM class function in the vendor specific interface
  49. driver. The latter has been used to switch back to the vendor
  50. specific configuration when the driver is probed for a class
  51. function.
  52. This workaround has several issues;
  53. - class driver blacklists is additional maintanence cruft in an
  54. unrelated driver
  55. - class driver blacklists prevents users from optionally running
  56. the devices in class mode
  57. - each device needs double match entries in the vendor driver
  58. - the initial probing as a class function slows down device
  59. discovery
  60. Now these issues have become even worse with the introduction of
  61. firmware supporting both NCM and ECM, where NCM ends up as the
  62. default mode in Linux. To use the same workaround, we now have
  63. to blacklist the devices in to two different class drivers and
  64. add yet another match entry to the vendor specific driver.
  65. This patch implements an alternative workaround strategy -
  66. independent of the interface drivers. It avoids adding a
  67. blacklist to the cdc_ncm driver and will let us remove the
  68. existing blacklist from the cdc_ether driver.
  69. As an additional bonus, removing the blacklists allow users to
  70. select one of the other device modes if wanted.
  71. Signed-off-by: Bjørn Mork <[email protected]>
  72. Signed-off-by: David S. Miller <[email protected]>
  73. ---
  74. drivers/net/usb/r8152.c | 113 ++++++++++++++++++++++++++++------------
  75. 1 file changed, 81 insertions(+), 32 deletions(-)
  76. --- a/drivers/net/usb/r8152.c
  77. +++ b/drivers/net/usb/r8152.c
  78. @@ -9675,6 +9675,9 @@ static int rtl8152_probe(struct usb_inte
  79. if (version == RTL_VER_UNKNOWN)
  80. return -ENODEV;
  81. + if (intf->cur_altsetting->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
  82. + return -ENODEV;
  83. +
  84. if (!rtl_vendor_mode(intf))
  85. return -ENODEV;
  86. @@ -9875,43 +9878,35 @@ static void rtl8152_disconnect(struct us
  87. }
  88. }
  89. -#define REALTEK_USB_DEVICE(vend, prod) { \
  90. - USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC), \
  91. -}, \
  92. -{ \
  93. - USB_DEVICE_AND_INTERFACE_INFO(vend, prod, USB_CLASS_COMM, \
  94. - USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), \
  95. -}
  96. /* table of devices that work with this driver */
  97. static const struct usb_device_id rtl8152_table[] = {
  98. /* Realtek */
  99. - REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8050),
  100. - REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8053),
  101. - REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8152),
  102. - REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153),
  103. - REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8155),
  104. - REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8156),
  105. + { USB_DEVICE(VENDOR_ID_REALTEK, 0x8050) },
  106. + { USB_DEVICE(VENDOR_ID_REALTEK, 0x8053) },
  107. + { USB_DEVICE(VENDOR_ID_REALTEK, 0x8152) },
  108. + { USB_DEVICE(VENDOR_ID_REALTEK, 0x8153) },
  109. + { USB_DEVICE(VENDOR_ID_REALTEK, 0x8155) },
  110. + { USB_DEVICE(VENDOR_ID_REALTEK, 0x8156) },
  111. /* Microsoft */
  112. - REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab),
  113. - REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6),
  114. - REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0927),
  115. - REALTEK_USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0c5e),
  116. - REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101),
  117. - REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f),
  118. - REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3054),
  119. - REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3062),
  120. - REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3069),
  121. - REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3082),
  122. - REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7205),
  123. - REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x720c),
  124. - REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7214),
  125. - REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x721e),
  126. - REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0xa387),
  127. - REALTEK_USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041),
  128. - REALTEK_USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff),
  129. - REALTEK_USB_DEVICE(VENDOR_ID_TPLINK, 0x0601),
  130. + { USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07ab) },
  131. + { USB_DEVICE(VENDOR_ID_MICROSOFT, 0x07c6) },
  132. + { USB_DEVICE(VENDOR_ID_MICROSOFT, 0x0927) },
  133. + { USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101) },
  134. + { USB_DEVICE(VENDOR_ID_LENOVO, 0x304f) },
  135. + { USB_DEVICE(VENDOR_ID_LENOVO, 0x3054) },
  136. + { USB_DEVICE(VENDOR_ID_LENOVO, 0x3062) },
  137. + { USB_DEVICE(VENDOR_ID_LENOVO, 0x3069) },
  138. + { USB_DEVICE(VENDOR_ID_LENOVO, 0x3082) },
  139. + { USB_DEVICE(VENDOR_ID_LENOVO, 0x7205) },
  140. + { USB_DEVICE(VENDOR_ID_LENOVO, 0x720c) },
  141. + { USB_DEVICE(VENDOR_ID_LENOVO, 0x7214) },
  142. + { USB_DEVICE(VENDOR_ID_LENOVO, 0x721e) },
  143. + { USB_DEVICE(VENDOR_ID_LENOVO, 0xa387) },
  144. + { USB_DEVICE(VENDOR_ID_LINKSYS, 0x0041) },
  145. + { USB_DEVICE(VENDOR_ID_NVIDIA, 0x09ff) },
  146. + { USB_DEVICE(VENDOR_ID_TPLINK, 0x0601) },
  147. {}
  148. };
  149. @@ -9931,7 +9926,61 @@ static struct usb_driver rtl8152_driver
  150. .disable_hub_initiated_lpm = 1,
  151. };
  152. -module_usb_driver(rtl8152_driver);
  153. +static int rtl8152_cfgselector_probe(struct usb_device *udev)
  154. +{
  155. + struct usb_host_config *c;
  156. + int i, num_configs;
  157. +
  158. + /* The vendor mode is not always config #1, so to find it out. */
  159. + c = udev->config;
  160. + num_configs = udev->descriptor.bNumConfigurations;
  161. + for (i = 0; i < num_configs; (i++, c++)) {
  162. + struct usb_interface_descriptor *desc = NULL;
  163. +
  164. + if (!c->desc.bNumInterfaces)
  165. + continue;
  166. + desc = &c->intf_cache[0]->altsetting->desc;
  167. + if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
  168. + break;
  169. + }
  170. +
  171. + if (i == num_configs)
  172. + return -ENODEV;
  173. +
  174. + if (usb_set_configuration(udev, c->desc.bConfigurationValue)) {
  175. + dev_err(&udev->dev, "Failed to set configuration %d\n",
  176. + c->desc.bConfigurationValue);
  177. + return -ENODEV;
  178. + }
  179. +
  180. + return 0;
  181. +}
  182. +
  183. +static struct usb_device_driver rtl8152_cfgselector_driver = {
  184. + .name = MODULENAME "-cfgselector",
  185. + .probe = rtl8152_cfgselector_probe,
  186. + .id_table = rtl8152_table,
  187. + .generic_subclass = 1,
  188. +};
  189. +
  190. +static int __init rtl8152_driver_init(void)
  191. +{
  192. + int ret;
  193. +
  194. + ret = usb_register_device_driver(&rtl8152_cfgselector_driver, THIS_MODULE);
  195. + if (ret)
  196. + return ret;
  197. + return usb_register(&rtl8152_driver);
  198. +}
  199. +
  200. +static void __exit rtl8152_driver_exit(void)
  201. +{
  202. + usb_deregister(&rtl8152_driver);
  203. + usb_deregister_device_driver(&rtl8152_cfgselector_driver);
  204. +}
  205. +
  206. +module_init(rtl8152_driver_init);
  207. +module_exit(rtl8152_driver_exit);
  208. MODULE_AUTHOR(DRIVER_AUTHOR);
  209. MODULE_DESCRIPTION(DRIVER_DESC);